/*****************************************************************************
*    Copyright (C)2004 Ali Corporation. All Rights Reserved.
*
*    File:    This file contains S3503 DVBS2 basic function in LLD.
*
*    Description:    Header file in LLD.
*    History:
*     Date  		  Author 	  Version   Reason
*     ============    =========   =======   =================
*       1.  08/29/2012      Russell	        Ver 0.1	         Create file for S3503 DVBS2 project
*       2.  01/29/2013      Russell         Ver 0.2          Add for C3503
*****************************************************************************/
#include "nim_S3503_DVBS.h"
#include <api/libsi/si_tdt.h>

//------------------------DEFINE for Work Mode--------------------------------//
//#define HW_ADPT_CR // when print, need to open
//#define RPT_CR_SNR_EST // print OldAdpt EST_NOISE value
#define NIM_CAPTURE_SUPPORT
#define ADC2DRAM_SUPPORT

#define DISEQC_DELAY    60   //adjust timing for DiSEqC circuit

//#define AUTOSCAN_DEBUG            // print log about AutoScan
// #define DEBUG_SOFT_SEARCH      // Try someone TP for special case, for DEbug
//#define DISEQC_OUT_INVERT       //DISEQC for Special Case
    
//----------------------End of DEFINE for Work Mode-----------------------------//

//----------------------------DEFINE for debug---------------------------------//
//-----defines for CR debug-------
//#define HW_ADPT_CR_MONITOR // print OldAdpt parameters
    
//#define HW_ADPT_NEW_CR_MONITOR // print CR coefficients, no matter OldAdpt or NewAdpt
//#define NEW_CR_ADPT_SNR_EST_RPT // print c/n dB value
//#define LLR_SHIFT_DEBUG // enable all LLR_SHIFT if 113[0]=1
//#define SW_ADPT_CR
//#define SW_SNR_RPT_ONLY


#ifdef HW_ADPT_CR_MONITOR
    #define ADPT_CR_PRINTF  libc_printf
#else
	#define ADPT_CR_PRINTF(...)
#endif

#ifdef HW_ADPT_NEW_CR_MONITOR
    #define ADPT_NEW_CR_PRINTF  libc_printf
#else
	#define ADPT_NEW_CR_PRINTF(...)
#endif

static UINT8  modcod_temp=0;
static UINT32  va_ber=0;
static UINT32  va_ber_window=0;
static UINT32  va_mer=0;
static UINT32  va_mer_window=0;
static UINT8   va_22k=0x00;
UINT8 S3503_Debug_Flag=0;
static UINT8 AutoScan_or_ChannelChange=1; ///default:1:channelchange_mode
   
#ifdef AUTOSCAN_DEBUG
	#define AUTOSCAN_PRINTF  libc_printf
    UINT16 config_data;
#else
	#define AUTOSCAN_PRINTF(...)
#endif

//----------------------------DEFINE for variable---------------------------------//
//extern varible
extern INT32 FFT_energy_1024[1024];
extern INT32 FFT_energy_1024_tmp[1024];
extern INT32 Frequency_Est[TP_MAXNUM];
extern INT32 SymbolRate_Est[TP_MAXNUM];
extern INT32 TP_number;
extern INT32 *channel_spectrum;
extern INT32 *channel_spectrum_tmp;
extern INT32 Last_Tuner_IF;
extern INT32 chlspec_Num;
extern INT32 called_num;
extern INT32 Final_Est_Freq;
extern INT32 Final_Est_SymRate;
extern INT32 Max_FFT_energy;

#define BYPASS_BUF_SIZE_DMA 0x10000  //64K bytes, size of ADC2MEM block in unit BYTE

static UINT32 last_ch_fc=0,last_tp_freq=0;
static INT32 fft_energy_store[1024];
static INT32 snr_initial_en; // Seen, 1 means first snr estimation done, set 1 in channel change

/* Name for the tuner, the last character must be Number for index */
static char nim_s3501_name[3][HLD_MAX_NAME_SIZE] =
{
	"NIM_S3503_0", "NIM_S3503_1", "NIM_S3503_2"
};

static UINT8 S3501ID[10] =
{
	0x47, 0x55, 0x33, 0x35, 0x30, 0x31, 0X44, 0x41, 0x54, 0x41
};

#ifdef NIM_CAPTURE_SUPPORT
static UINT32  capture_debug_en = 0;//use for capture
static UINT32  capture_startFreq = 950;
#endif

static const UINT8 MAP_BETA_ACTIVE_BUF[32] =
{
	0x00,   //  						 //index 0, do not use
	0x01,   // 1/4 of QPSK  	  //1
	0x01,   // 1/3  					//2
	0x01,   // 2/5  					//3
	0x01,   // 1/2  					//4
	0x01,   // 3/5  					//5
	0x01,   // 2/3  					//6
	0x01,   // 3/4  					//7
	0x01,   // 4/5  					//8
	0x01,   // 5/6  					//9
	0x01,   // 8/9  					//a
	0x01,   // 9/10 					//b
	0x01,   // 3/5 of 8PSK  		 //c
	0x01,   // 2/3  					//d
	0x01,   // 3/4  					//e
	0x01,   // 5/6  					//f
	0x01,   // 8/9  					//10
	0x01,   // 9/10 					//11
	0x01,   // 2/3 of 16APSK		//12
	0x01,   // 3/4  					//13
	0x01,   // 4/5  					//14
	0x01,   // 5/6  					//15
	0x01,   // 8/9  					//16
	0x01,   // 9/10 					//17
	0x01,   // for 32 APSK, dont use
	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
};

static const UINT8 MAP_BETA_BUF_LLR_SHIFT_OFF[32] =
{
	188,   //  205,		// index 0, do not use
	188,   //  205,		// 1/4 of QPSK    //1
	190,   //  230,		// 1/3  					//2
	205,   //  205,		// 2/5  					//3
	205,   //  205,		// 1/2  					//4
	180,   //  180,		// 3/5  					//5
	180,   //  180,		// 2/3  					//6
	180,   //  180,		// 3/4  					//7
	155,   //  180,		// 4/5  					//8
	168,   //  180,		// 5/6  					//9
	150,   //  155,		// 8/9  					//a
	150,   //  155,		// 9/10 					//b
	215,   //  180,		// 3/5 of 8PSK  		 //c
	185,   //  180,		// 2/3  					//d
	145,   //  180,		// 3/4  					//e
	145,   //  155,		// 5/6  					//f
	145,   //  155,		// 8/9  					//10
	140,   //  155,		// 9/10 					//11
	185,   //  205,		// 2/3 of 16APSK		//12
	165,   //  180,		// 3/4  					//13
	145,   //  180,		// 4/5  					//14
	130,   //  155,		// 5/6  					//15
	145,   //  155,		// 8/9  					//16
	130,   //  155,		// 9/10 					//17
	145,	//3/4-    for 32 APSK, 
	120, 	// 4/5
	155, 	 //5/6
	140,   // 8/9
	125,   // 9/10
	155, 
	155, 
	155
};

static const UINT8 MAP_BETA_BUF_LLR_SHIFT_ON[32] =
{
	188,   //  205,		// index 0, do not use
	188,   //  205,		// 1/4 of QPSK    //1
	190,   //  230,		// 1/3  					//2
	205,   //  205,		// 2/5  					//3
	205,   //  205,		// 1/2  					//4
	180,   //  180,		// 3/5  					//5
	180,   //  180,		// 2/3  					//6
	180,   //  180,		// 3/4  					//7
	155,   //  180,		// 4/5  					//8
	168,   //  180,		// 5/6  					//9
	150,   //  155,		// 8/9  					//a
	150,   //  155,		// 9/10 					//b
	215,   //  180,		// 3/5 of 8PSK  		 //c
	185,   //  180,		// 2/3  					//d
	140,   //  180,		// 3/4  					//e
	230,   //  155,		// 5/6  					//f
	160,   //  155,		// 8/9  					//10
	155,   //  155,		// 9/10 					//11
	185,   //  205,		// 2/3 of 16APSK		//12
	155,   //  180,		// 3/4  					//13
	140,   //  180,		// 4/5  					//14
	160,   //  155,		// 5/6  					//15
	160,   //  155,		// 8/9  					//16
	160,   //  155,		// 9/10 					//17
	145,	//3/4-    for 32 APSK, 
	120, 	// 4/5
	145, 	 //5/6
	135,   // 8/9
	130,   // 9/10
	135, 
	155, 
	155
};

static const UINT16 DEMAP_NOISE[32] =
{
	0x00,   	// index 0, do not use
	0x16b,  	// 1/4 of QPSK  		//1
	0x1d5,  	// 1/3  					//2
	0x246,  	// 2/5  					//3
	0x311,  	// 1/2  					//4
	0x413,  	// 3/5  					//5
	0x4fa,  	// 2/3  					//6
	0x62b,  	// 3/4  					//7
	0x729,  	// 4/5  					//8
	0x80c,  	// 5/6  					//9
	0xa2a,  	// 8/9  					//a
	0xab2,  	// 9/10 					//b
	0x8a9,  	// 3/5 of 8PSK  		 //c
	0xb31,  	// 2/3  					//d
	0xf1d,   // 3/4 					 //e
	0x1501, 	// 5/6  					//f
	0x1ca5, 	  // 8/9					  //10
	0x1e91, 	  // 9/10   				  //11
	0x133b, 	  // 2/3 of 16APSK  	  //12
	0x199a, 	  // 3/4					  //13
	0x1f08, 	  // 4/5					  //14
	0x234f, 	  // 5/6					  //15
	0x2fa1, 	  // 8/9					  //16
	0x3291, 	   // 9/10  				   //17
	0x00,   	 // for 32 APSK, dont use
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

static const UINT8 snr_tab[177] =
{
	0, 1, 3, 4, 5, 7, 8,\
	9, 10, 11, 13, 14, 15, 16, 17,\
	18, 19, 20, 21, 23, 24, 25, 26,\
	26, 27, 28, 29, 30, 31, 32, 33,\
	34, 35, 35, 36, 37, 38, 39, 39,\
	40, 41, 42, 42, 43, 44, 45, 45,\
	46, 47, 47, 48, 49, 49, 50, 51,\
	51, 52, 52, 53, 54, 54, 55, 55,\
	56, 57, 57, 58, 58, 59, 59, 60,\
	61, 61, 62, 62, 63, 63, 64, 64,\
	65, 66, 66, 67, 67, 68, 68, 69,\
	69, 70, 70, 71, 72, 72, 73, 73,\
	74, 74, 75, 76, 76, 77, 77, 78,\
	79, 79, 80, 80, 81, 82, 82, 83,\
	84, 84, 85, 86, 86, 87, 88, 89,\
	89, 90, 91, 92, 92, 93, 94, 95,\
	96, 96, 97, 98, 99, 100, 101, 102,\
	102, 103, 104, 105, 106, 107, 108, 109,\
	110, 111, 113, 114, 115, 116, 117, 118,\
	119, 120, 122, 123, 124, 125, 127, 128,\
	129, 131, 132, 133, 135, 136, 138, 139,\
	141, 142, 144, 145, 147, 148, 150, 152,\
	153, 155
};

static const UINT32 agc_table[256] = {
	  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   2,   3,   4,   5, \
  6,   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21, \
 22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37, \
 38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  52,  55,  57, \
 60,  62,  65,  67,  70,  72,  75,  77,  78,  79,  80,  82,  83,  84,  85,  87, \
 88,  89,  90,  92,  93,  94,  95,  97,  98,  99, 101, 102, 103, 104, 105, 106, \
107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, \
123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, \
139, 140, 141, 142, 144, 145, 146, 147, 149, 150, 151, 152, 154, 155, 156, 157, \
159, 160, 161, 162, 164, 165, 166, 167, 169, 170, 171, 173, 175, 176, 178, 180, \
182, 184, 187, 189, 192, 194, 197, 199, 202, 204, 207, 209, 212, 215, 218, 222, \
225, 228, 232, 235, 238, 242, 245, 248, 252, 255, 258, 262, 265, 268, 272, 275, \
278, 282, 285, 288, 292, 295, 298, 302, 305, 308, 312, 317, 322, 327, 332, 337, \
342, 347, 352, 357, 362, 367, 372, 377, 382, 387, 392, 397, 402, 407, 412, 417, \
422, 427, 432, 437, 442, 447, 452, 457, 462, 467, 472, 477, 482, 487, 492, 493, \
494, 495, 496, 497, 498, 499, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, \
};

//--------Function essential progess --------
    static DWORD nim_s3503_multu64div(UINT32 v1, UINT32 v2, UINT32 v3);
static INT32 nim_s3503_open(struct nim_device *dev);
static INT32 nim_s3503_close(struct nim_device *dev);
static INT32 nim_s3503_ioctl(struct nim_device *dev, INT32 cmd, UINT32 param);
static INT32 nim_s3503_task_init(struct nim_device *dev);
static void nim_s3503_task(UINT32 param1, UINT32 param2);
static INT32 nim_s3503_channel_change(struct nim_device *dev, UINT32 freq, UINT32 sym, UINT8 fec);
static INT32 nim_s3503_channel_search(struct nim_device *dev, UINT32 CRNum);
static  INT32 nim_s3503_soft_search(struct nim_device *dev, UINT32 *rs, UINT32 *freq, INT32 delfreq);
static  INT32 nim_s3503_adc2mem_cap(struct nim_device *dev, UINT32 startFreq, UINT32 sym, UINT32 *cap_buffer, UINT32 dram_len);
static  INT32 nim_s3503_cap(struct nim_device *dev, UINT32 startFreq, UINT32 *cap_buffer, UINT32 sym);
//--------Function system config---------
static INT32 nim_s3503_hw_init(struct nim_device *dev);
static INT32 nim_s3503_autoscan_initial (struct nim_device *dev);
static INT32 nim_s3503_set_demod_ctrl(struct nim_device *dev, UINT8 c_Value);
static INT32 nim_s3503_set_polar(struct nim_device *dev, UINT8 polar);
static INT32 nim_s3503_set_12v(struct nim_device *dev, UINT8 flag);
static INT32 nim_s3503_set_ext_LNB(struct nim_device *dev, struct QPSK_TUNER_CONFIG_API *ptrQPSK_Tuner);
static INT32 nim_s3503_set_adc(struct nim_device *dev);
static INT32 nim_s3503_set_dsp_clk(struct nim_device *dev, UINT8 clk_sel);
static INT32 nim_s3503_set_agc1(struct nim_device *dev, UINT8 low_sym, UINT8 s_Case);
static  void nim_s3503_set_RS(struct nim_device *dev, UINT32 rs);
static  void nim_s3503_set_freq_offset(struct nim_device *dev, INT32 delfreq);
static INT32 nim_s3503_set_acq_workmode(struct nim_device *dev, UINT8 s_Case);
static INT32 nim_s3503_set_hw_timeout(struct nim_device *dev, UINT8 time_thr);
static INT32 nim_s3503_set_hbcd_timeout(struct nim_device *dev, UINT8 s_Case);
static INT32 nim_s3503_set_dynamic_power(struct nim_device *dev, UINT8 snr);
static INT32 nim_s3503_set_RS_Search_Range(struct nim_device *dev, UINT8 s_Case, UINT32 rs);
static INT32 nim_s3503_set_FC_Search_Range(struct nim_device *dev, UINT8 s_Case, UINT32 rs);
static INT32 nim_s3503_TR_CR_Setting(struct nim_device *dev, UINT8 s_Case);
static INT32 nim_s3503_ldpc_keep_working_enable(struct nim_device *dev);
static INT32 nim_s3503_ldpc_keep_working_disable(struct nim_device *dev);
static INT32 nim_s3503_set_ldpc_iter_para(struct nim_device *dev, UINT16 most_cnt, UINT8 least_cnt, UINT8 exit_cnt_thld);
static INT32 nim_s3503_get_LDPC_iter_cnt(struct nim_device *dev, UINT16 *iter_cnt);
static INT32 nim_s3503_set_LDPC_iter_cnt_record_last(struct nim_device *dev);
static INT32 nim_s3503_set_LDPC_iter_cnt_record_max(struct nim_device *dev);
static INT32 nim_s3503_debug_intask(struct nim_device *dev);
//--------Function software support---------
static INT32 nim_s3503_sym_config(struct nim_device *dev, UINT32 sym);
static INT32 nim_s3503_set_err(struct nim_device *dev);
static INT32 nim_s3503_clear_err(struct nim_device *dev);
//-------function for digital signal processing------
static INT32 nim_s3503_FFT(struct nim_device *dev, UINT32 startFreq);
static  void nim_s3503_FFT_set_para(struct nim_device *dev);

// -------function  for tuner DiSEqC------------
static INT32 nim_s3503_DiSEqC_initial(struct nim_device *dev);
static INT32 nim_s3503_DiSEqC_operate(struct nim_device *dev, UINT32 mode, UINT8 *cmd, UINT8 cnt);
static INT32 nim_s3503_DiSEqC2X_operate(struct nim_device *dev, UINT32 mode, UINT8 *cmd, UINT8 cnt, UINT8 *rt_value, UINT8 *rt_cnt);

// -------function  for interrupt------------
static INT32 nim_s3503_interrupt_mask_clean(struct nim_device *dev);
static  void nim_s3503_interrupt_clear(struct nim_device *dev);

// -------function  for tuner FEC------------
static INT32 nim_s3503_fec_set_ldpc(struct nim_device *dev, UINT8 s_Case, UINT8 c_ldpc, UINT8 c_fec);
static void nim_s3503_fec_set_demap_noise(struct nim_device *dev);
static INT32 nim_s3503_fec_llr_shift(struct nim_device *dev);

//-------function for capture by register-------------
static INT32 nim_s3503_cap_IQ_enerage(struct nim_device *dev);
static INT32 nim_s3503_cap_start(struct nim_device *dev, UINT32 startFreq, UINT32 sym, UINT32 *cap_buffer);
static  INT32 nim_s3503_cap_fft_find_channel(struct nim_device *dev, UINT32 *tune_freq);
static  void nim_s3503_cap_calculate_energy(struct nim_device *dev);
static  void nim_s3503_cap_fft_result_read(struct nim_device *dev);


// -------function for frequency offset------------
static INT32 nim_s3503_freq_offset_set(struct nim_device *dev, UINT8 low_sym, UINT32 *s_Freq);
static INT32 nim_s3503_freq_offset_reset(struct nim_device *dev, UINT8 low_sym);
static INT32 nim_s3503_freq_offset_reset1(struct nim_device *dev, UINT8 low_sym, INT32 delfreq);

// -------function for TR------------
static INT32 nim_s3503_tr_setting(struct nim_device *dev, UINT8 s_Case);

// -------function for CR------------
static INT32 nim_s3503_cr_setting(struct nim_device *dev, UINT8 s_Case);
static INT32 nim_s3503_cr_sw_adaptive(struct nim_device *dev);
static INT32 nim_s3503_cr_sw_snr_rpt(struct nim_device *dev);
static INT32 nim_s3503_cr_tab_init(struct nim_device *dev);
static INT32 nim_s3503_cr_set_phase_noise(struct nim_device *dev);
static INT32 nim_s3503_cr_adaptive_initial (struct nim_device *dev);
static INT32 nim_s3503_cr_adaptive_configure (struct nim_device *dev, UINT32 sym);
static void nim_s3503_cr_adaptive_monitor (struct nim_device *dev);
static INT32 nim_s3503_cr_adaptive_method_choice(struct nim_device *dev, UINT8 choice_type);
static INT32 nim_s3503_cr_new_tab_init(struct nim_device *dev);
static void nim_s3503_cr_new_adaptive_monitor(struct nim_device *dev);
static INT32 nim_s3503_cr_new_modcod_table_init(struct nim_device *dev,UINT32 sym);
static INT32 nim_s3503_cr_new_adaptive_unlock_monitor(struct nim_device *dev);

// -------function for tso------------
static INT32 nim_s3503_tso_initial (struct nim_device *dev, UINT8 insert_dummy, UINT8 tso_mode);
static INT32 nim_s3503_tso_dummy_off (struct nim_device *dev);
static INT32 nim_s3503_tso_dummy_on (struct nim_device *dev);
static INT32 nim_s3503_tso_soft_cbr_on (struct nim_device *dev, UINT32 bitrate);
static INT32 nim_s3503_tso_soft_cbr_off (struct nim_device *dev);
static INT32 nim_s3503_tso_bypass (struct nim_device *dev);
static INT32 nim_s3503_tso_off (struct nim_device *dev);
static INT32 nim_s3503_tso_on (struct nim_device *dev);
// -------function for ADC2DRAM------------
static INT32 nim_s3503_adc2mem_start(struct nim_device *dev, UINT32 startFreq, UINT32 sym, UINT32 *cap_buffer, UINT32 dram_len);
static  INT32 nim_s3503_adc2mem_entity(struct nim_device *dev,  UINT8 *cap_buffer, UINT32 dram_len);
static  INT32 nim_s3503_adc2mem_calculate_energy(struct nim_device *dev,UINT8 *cap_buffer,UINT32 dram_len);
//--------Function get demod register---------
static INT32 nim_s3503_get_lock(struct nim_device *dev, UINT8 *lock);
static INT32 nim_s3503_get_freq(struct nim_device *dev, UINT32 *freq);
static INT32 nim_s3503_get_freqoffset(struct nim_device *dev);
static INT32 nim_s3503_get_symbol_rate(struct nim_device *dev, UINT32 *sym_rate);
static INT32 nim_s3503_get_code_rate(struct nim_device *dev, UINT8 *code_rate);
static INT32 nim_s3503_get_AGC(struct nim_device *dev, UINT8 *agc);
static INT32 nim_s3503_get_SNR(struct nim_device *dev, UINT8 *snr);
static INT32 nim_s3503_get_BER(struct nim_device *dev, UINT32 *RsUbc);
static INT32 nim_s3503_get_PER(struct nim_device *dev, UINT32 *RsUbc);
static INT32 nim_s3503_get_LDPC(struct nim_device *dev, UINT32 *RsUbc);
static INT32 nim_s3503_get_fft_result(struct nim_device *dev, UINT32 freq, UINT32 *start_adr);
static INT32 nim_s3503_get_type(struct nim_device *dev);
static INT32 nim_s3503_get_dsp_clk(struct nim_device *dev, UINT32 *sample_rate);
static  INT32 nim_s3503_get_tune_freq(struct nim_device *dev, INT32 *freq);
static  UINT8 nim_s3503_get_SNR_index(struct nim_device *dev);
static INT32 nim_s3503_get_bit_rate(struct nim_device *dev, UINT8 work_mode, UINT8 map_type, UINT8 code_rate, UINT32 Rs, UINT32 *bit_rate);
static INT32 nim_s3503_get_type(struct nim_device *dev);
static INT32 nim_s3503_get_err(struct nim_device *dev);
static INT32 nim_s3503_get_new_BER(struct nim_device *dev, UINT32 *ber);
static INT32 nim_s3503_check_BER(struct nim_device *dev, UINT32 *RsUbc);
static INT32 nim_s3503_get_new_PER(struct nim_device *dev, UINT32 *per);
static INT32 nim_s3503_get_MER(struct nim_device *dev, UINT32 *mer);
static INT32 nim_s3503_get_snr_db(struct nim_device *dev,UINT16 *snr_db); 
static INT32 nim_s3503_get_phase_error(struct nim_device *dev, INT32 *phase_error);
static INT32 nim_s3503_get_bypass_buffer(struct nim_device *dev);
static  UINT32 nim_s3503_get_CURFreq(struct nim_device *dev);
static  UINT8 nim_s3503_get_CRNum(struct nim_device *dev);
static  INT32 nim_s3503_get_bitmode(struct nim_device *dev, UINT8 *bitMode);
static INT32 nim_s3503_set_32apsk_target(struct nim_device *dev);
static  INT32 nim_s3503_reg_get_freq(struct nim_device *dev, UINT32 *freq);
static  INT32 nim_s3503_reg_get_symbol_rate(struct nim_device *dev, UINT32 *sym_rate);
static  INT32 nim_s3503_reg_get_code_rate(struct nim_device *dev, UINT8 *code_rate);
static INT32 nim_s3503_reg_get_map_type(struct nim_device *dev, UINT8 *map_type);
static INT32 nim_s3503_reg_get_work_mode(struct nim_device *dev, UINT8 *work_mode);
static INT32 nim_s3503_reg_get_iqswap_flag(struct nim_device *dev, UINT8 *iqswap_flag);
static INT32 nim_s3503_reg_get_roll_off(struct nim_device *dev, UINT8 *roll_off);
static INT32 nim_s3503_reg_get_modcod(struct nim_device *dev, UINT8 *modcod);
static INT32 nim_s3503_NframeStepTso_setting(struct nim_device *dev,UINT32 *sym_rate,UINT8 s_Case);


/*****************************************************************************
Name:
    multu64div
Description:
    This function implment v1*v2/v3. And v1*v2 is 64 bit
Parameters:
    [IN]
    [OUT]
Return:
***********************************************************************/
//Get HI value from the multple result
#ifdef WIN32
DWORD nim_s3503_multu64div(UINT32 v1, UINT32 v2, UINT32 v3)
{
    DWORD v;
    if (v3 == 0)
        return 0;
	v = (UINT64)(v1)*(UINT64)(v2)/v3;
	return v;
}
#else
# define mult64hi(v1, v2)           \
({  DWORD __ret;            \
    __asm__ volatile(                   \
        "multu  %1, %2\n    "               \
        "mfhi %0\n" \
         : "=r" (__ret)         \
         : "r" (v1), "r"(v2));                  \
    __ret;                      \
})
//Get LO value from the multple result
# define mult64lo(v1, v2)           \
({  DWORD __ret;            \
    __asm__ volatile(                   \
        "multu  %1, %2\n    "               \
        "mflo %0\n" \
         : "=r" (__ret)         \
         : "r" (v1), "r"(v2));                  \
    __ret;                      \
})
DWORD nim_s3503_multu64div(UINT32 v1, UINT32 v2, UINT32 v3)
{
    DWORD hi, lo;
    UINT64 tmp;
    DWORD *tmp64;
    DWORD ret;
    if (v3 == 0)
        return 0;
    hi = mult64hi(v1, v2);
    lo = mult64lo(v1, v2);
    tmp64 = ((DWORD *)(&tmp))+1;
    *tmp64-- = hi;
    *tmp64 = lo;
    //Few nop here seems required, if no nop is here,
    //then the result wont be correct.
    //I guess maybe this is caused by some GCC bug.
    //Because I had checked the compiled result between with nop and without nop,
    //they are quite different!! I dont have time to search more GCC problem,
    //Therefore, I can only leave the nop here quietly. :(
    //--Michael 2003/10/10
    __asm__("nop; nop; nop; nop");
    ret = tmp/v3;
    return ret;
}
#endif
//-------------------------------------

/*****************************************************************************
* INT32 nim_reg_read(struct nim_device *dev, UINT8 bMemAdr, UINT8 *pData, UINT8 bLen)
* Description: S3501 register read function
*                   Can read 8-byte one time and bLen must no more than 8
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8 pol
*
* Return Value: void
*****************************************************************************/
static INT32 nim_reg_read(struct nim_device *dev, UINT16 bMemAdr, UINT8 *pData, UINT8 bLen)
{
	INT32 err;
	UINT8 i;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;


	pData[0] = bMemAdr;
	if (bLen > 8)
	{
		nim_s3503_set_err(dev);
		return ERR_FAILUE;
	}

	for (i = 0; i < bLen; i++)
	{
		pData[i ] = NIM_GET_BYTE(NIM_S3503_BASE_ADDR+bMemAdr+i);
	}

	return SUCCESS;
}

/*****************************************************************************
* INT32 nim_reg_write(struct nim_device *dev, UINT8 bMemAdr, UINT8 *pData, UINT8 bLen)
* Description: S3501 register write function
*                   Can write 8-byte one time and bLen must no more than 8
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8 pol
*
* Return Value: void
*****************************************************************************/
static INT32 nim_reg_write(struct nim_device *dev, UINT16 bMemAdr, UINT8 *pData, UINT8 bLen)
{
	int err;
	UINT8 i, buffer[8];
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;


	if (bLen >8)
	{
		nim_s3503_set_err(dev);
		return ERR_FAILUE;
	}

	for (i = 0; i < bLen; i++)
	{
		NIM_SET_BYTE(NIM_S3503_BASE_ADDR+bMemAdr+i,pData[i]);
	}

	return SUCCESS;
}

/*****************************************************************************
* INT32 nim_s3503_attach (struct QPSK_TUNER_CONFIG_API * ptrQPSK_Tuner)
* Description: S3501 initialization
*
* Arguments:
*  none
*
* Return Value: INT32
*****************************************************************************/
INT32 nim_s3503_attach(struct QPSK_TUNER_CONFIG_API *ptrQPSK_Tuner)
{
	static unsigned char nim_dev_num = 0;
	struct nim_device *dev;
	struct nim_s3501_private *priv_mem;
	if (ptrQPSK_Tuner == NULL)
	{
		NIM_PRINTF("Tuner Configuration API structure is NULL!/n");
		return ERR_NO_DEV;
	}
	if (nim_dev_num > 2)
	{
		NIM_PRINTF("Can not support three or more S3501 !/n");
		return ERR_NO_DEV;
	}

	dev = (struct nim_device *) dev_alloc((unsigned char *)nim_s3501_name[nim_dev_num], HLD_DEV_TYPE_NIM, sizeof(struct nim_device));
	if (dev == NULL)
	{
		NIM_PRINTF("Error: Alloc nim device error!\n");
		return ERR_NO_MEM;
	}

	priv_mem = (struct nim_s3501_private *) comm_malloc(sizeof(struct nim_s3501_private));
	if (priv_mem == NULL)
	{
		dev_free(dev);
		NIM_PRINTF("Alloc nim device prive memory error!/n");
		return ERR_NO_MEM;
	}
	comm_memset((int *)priv_mem, 0, sizeof(struct nim_s3501_private));
	dev->priv = (void *) priv_mem;
	//diseqc state init
	dev->diseqc_info.diseqc_type = 0;
	dev->diseqc_info.diseqc_port = 0;
	dev->diseqc_info.diseqc_k22 = 0;

	if ((ptrQPSK_Tuner->config_data.QPSK_Config & M3501_POLAR_REVERT) == M3501_POLAR_REVERT) //bit4: polarity revert.
		dev->diseqc_info.diseqc_polar = LNB_POL_V;
	else //default usage, not revert.
		dev->diseqc_info.diseqc_polar = LNB_POL_H;

	dev->diseqc_typex = 0;
	dev->diseqc_portx = 0;

	/* Function point init */
	dev->base_addr = ptrQPSK_Tuner->ext_dm_config.i2c_base_addr;
	dev->init = nim_s3503_attach;
	dev->open = nim_s3503_open;
	dev->stop = nim_s3503_close;
	dev->do_ioctl = nim_s3503_ioctl;
	dev->do_ioctl_ext = nim_s3503_ioctl_ext;
	dev->get_lock = nim_s3503_get_lock;
	dev->get_freq = nim_s3503_get_freq;
	dev->get_FEC = nim_s3503_get_code_rate;
	dev->get_SNR = nim_s3503_get_SNR;
      dev->set_polar = nim_s3503_set_polar;
      dev->set_12v = nim_s3503_set_12v;
      dev->channel_search = nim_s3503_channel_search;
      dev->DiSEqC_operate = nim_s3503_DiSEqC_operate;
      dev->DiSEqC2X_operate = nim_s3503_DiSEqC2X_operate;
      dev->get_sym = nim_s3503_get_symbol_rate;
      dev->get_AGC = nim_s3503_get_AGC;
      dev->get_BER = nim_s3503_get_BER;
      dev->get_fft_result = nim_s3503_get_fft_result;
      dev->get_ver_infor = NULL;//nim_s3503_get_ver_infor;

	/* tuner configuration function */
	priv_mem->nim_Tuner_Init = ptrQPSK_Tuner->nim_Tuner_Init;
	priv_mem->nim_Tuner_Control = ptrQPSK_Tuner->nim_Tuner_Control;
	priv_mem->nim_Tuner_Status = ptrQPSK_Tuner->nim_Tuner_Status;
	priv_mem->i2c_type_id = ptrQPSK_Tuner->tuner_config.i2c_type_id;
	priv_mem->Tuner_Config_Data.QPSK_Config = ptrQPSK_Tuner->config_data.QPSK_Config;
	priv_mem->ext_dm_config.i2c_type_id = ptrQPSK_Tuner->ext_dm_config.i2c_type_id;
	priv_mem->ext_dm_config.i2c_base_addr = ptrQPSK_Tuner->ext_dm_config.i2c_base_addr;

	priv_mem->ul_status.m_enable_dvbs2_hbcd_mode = 0;
	priv_mem->ul_status.m_dvbs2_hbcd_enable_value = 0x7f;
	priv_mem->ul_status.nim_s3501_sema = OSAL_INVALID_ID;
	priv_mem->ul_status.s3501_autoscan_stop_flag = 0;
	priv_mem->ul_status.s3501_chanscan_stop_flag = 0;
	priv_mem->ul_status.old_ber = 0;
	priv_mem->ul_status.old_per = 0;
	priv_mem->ul_status.m_hw_timeout_thr = 0;
	priv_mem->ul_status.old_ldpc_ite_num = 0;
	priv_mem->ul_status.c_RS = 0;
	priv_mem->ul_status.phase_err_check_status = 0;
	priv_mem->ul_status.s3501d_lock_status = NIM_LOCK_STUS_NORMAL;
	priv_mem->ul_status.m_s3501_type = 0x00;
	priv_mem->ul_status.m_setting_freq = 123;
	priv_mem->ul_status.m_Err_Cnts = 0x00;
	priv_mem->tsk_status.m_lock_flag = NIM_LOCK_STUS_NORMAL;
	priv_mem->tsk_status.m_task_id = 0x00;
	priv_mem->t_Param.t_aver_snr = -1;
	priv_mem->t_Param.t_last_iter = -1;
	priv_mem->t_Param.t_last_snr = -1;
	priv_mem->t_Param.t_snr_state = 0;
	priv_mem->t_Param.t_snr_thre1 = 256;
	priv_mem->t_Param.t_snr_thre2 = 256;
	priv_mem->t_Param.t_snr_thre3 = 256;
	priv_mem->t_Param.t_dynamic_power_en = 0;
	priv_mem->t_Param.t_phase_noise_detected = 0;
	priv_mem->t_Param.t_reg_setting_switch = 0x0f;
	priv_mem->t_Param.t_i2c_err_flag = 0x00;
	priv_mem->flag_id = OSAL_INVALID_ID;
	priv_mem->blscan_mode = NIM_SCAN_SLOW; // this mode may abandoned

	/* Add this device to queue */
	if (dev_register(dev) != SUCCESS)
	{
		NIM_PRINTF("Error: Register nim device error!\n");
		comm_free((int*)priv_mem);
		dev_free(dev);
		return ERR_NO_DEV;
	}
	nim_dev_num++;
	priv_mem->ul_status.nim_s3501_sema = NIM_MUTEX_CREATE(1);

	priv_mem->m3501_mutex= osal_mutex_create();
	if(priv_mem->m3501_mutex == OSAL_INVALID_ID)
	{
		NIM_PRINTF("Error: Register nim device error!\n");
		return ERR_FAILUE;
	}
	
	// Initial the QPSK Tuner
	if (priv_mem->nim_Tuner_Init != NULL)
	{
		NIM_PRINTF(" Initial the Tuner \n");
		if (((struct nim_s3501_private *) dev->priv)->nim_Tuner_Init(&priv_mem->tuner_id, &(ptrQPSK_Tuner->tuner_config)) != SUCCESS)
		{
			NIM_PRINTF("Error: Init Tuner Failure!\n");


			return ERR_NO_DEV;
		}
	}

	nim_s3503_set_ext_LNB(dev, ptrQPSK_Tuner);

	nim_s3503_get_type(dev);

	ptrQPSK_Tuner->device_type = priv_mem->ul_status.m_s3501_type;

	return SUCCESS;
}

/*****************************************************************************
* INT32 nim_s3503_hw_check(struct nim_device *dev)
* Description: S3501 set polarization
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8 pol
*
* Return Value: void
*****************************************************************************/
static INT32 nim_s3503_hw_check(struct nim_device *dev)
{
	UINT8 data;
	NIM_PRINTF("    Enter fuction nim_s3503_hw_check\n");

	nim_reg_read(dev, RA3_CHIP_ID + 0x01, &data, 1);
	if (data != 0x35)
		return ERR_FAILED;
	else
		return SUCCESS;
}

/*****************************************************************************
*static void nim_s3503_fec_set_demap_noise(struct nim_device *dev)
* Description: S3501 set polarization
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8 pol
*
* Return Value: void
*****************************************************************************/
static void nim_s3503_fec_set_demap_noise(struct nim_device *dev)
{
	UINT8 data, noise_index;
	UINT16 est_noise;

	// activate noise
	nim_reg_read(dev, RD0_DEMAP_NOISE_RPT + 2, &data, 1);
	data &= 0xfc;
	nim_reg_write(dev, RD0_DEMAP_NOISE_RPT + 2, &data, 1);

	// set noise_index
	noise_index = 0x0c; // 8psk,3/5.
	nim_reg_write(dev, RD0_DEMAP_NOISE_RPT + 1, &noise_index, 1);

	// set noise
	est_noise = DEMAP_NOISE[noise_index];
	data = est_noise & 0xff;
	nim_reg_write(dev, RD0_DEMAP_NOISE_RPT, &data, 1);
	data = (est_noise >> 8) & 0x3f;
	data |= 0xc0;
	nim_reg_write(dev, RD0_DEMAP_NOISE_RPT + 1, &data, 1);
	//  }
}

/*****************************************************************************
* void nim_s3503_after_reset_set_param(struct nim_device *dev)
* Description: S3501 set polarization
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8 pol
*
* Return Value: void
*****************************************************************************/
static void nim_s3503_after_reset_set_param(struct nim_device *dev)
{
	UINT8 data;//,data1;
        UINT32 data_tmp;
	int i;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

	nim_s3503_set_demod_ctrl(dev, NIM_DEMOD_CTRL_0X91);

	nim_s3503_interrupt_mask_clean(dev);
    data = 0x50; 
    nim_reg_write(dev, R0A_AGC1_LCK_CMD, &data, 1);

	// set diseqc clock.
        nim_s3503_get_dsp_clk(dev, &data_tmp);
    // Set diseqc parameter
        data=((data_tmp+500)/1000);
    nim_reg_write(dev, R90_DISEQC_CLK_RATIO, &data, 1);

    // set unconti timer
    data = 0x40;
    nim_reg_write(dev, RBA_AGC1_REPORT, &data, 1);

    //set receive timer: 0x88 for default;
    data = 0x88;
    nim_reg_write(dev, R8E_DISEQC_TIME, &data, 1);
    data = 0xff;
    nim_reg_write(dev, R8E_DISEQC_TIME + 0x01, &data, 1);
	// M3501C_DCN : may move those register to HW_INI
#ifdef DISEQC_OUT_INVERT
	// cr96[7] is DISEQC invert
	nim_reg_read(dev, R90_DISEQC_CLK_RATIO+6, &data, 1);
	data = data | 0x80;
	nim_reg_write(dev, R90_DISEQC_CLK_RATIO+6, &data, 1);
#endif
	// Open new tso
	// bit0: tso_bist, bit1, insert dummy, bit2, sync_lenght, bit3, vld gate,
	// bit 4, cap_eco_en, bit5, cap pid enable ,
	// bit[7:6] dsp clk sel: 00: 90m, 01:98m, 10:108m, 11:135m
	data = 0x12;
	nim_reg_write(dev, RF0_HW_TSO_CTRL, &data, 1);

    // set TSO fifo burst mode (input 8 byte start output)
	nim_reg_read(dev, RF1_DSP_CLK_CTRL, &data, 1);
	data = data | 0x40;
	nim_reg_write(dev, RF1_DSP_CLK_CTRL, &data, 1);

	// TSO OEJ
	nim_reg_read(dev, RF0_HW_TSO_CTRL+5, &data, 1);
	data =data & 0xef;
	nim_reg_write(dev, RF0_HW_TSO_CTRL+5, &data, 1);

	// Set TSO bitrate margin, unit 1/16M,
	data = 0x08;
	nim_reg_write(dev, RF0_HW_TSO_CTRL+2, &data, 1);
    for (i = 0; i < 32; i++)
    {
        data = i;
        nim_reg_write(dev, R9C_DEMAP_BETA + 0x02, &data, 1);
        data = MAP_BETA_ACTIVE_BUF[i];
        nim_reg_write(dev, R9C_DEMAP_BETA, &data, 1);
        data = 0x04;
        nim_reg_write(dev, R9C_DEMAP_BETA + 0x03, &data, 1);
      // For C3503 only
       if(priv->ul_status.m_s3501_sub_type == NIM_C3503_SUB_ID)
       {       
        if(S2_LLR_SHIFT[i])
        	data = MAP_BETA_BUF_LLR_SHIFT_ON[i];
        else
        	data = MAP_BETA_BUF_LLR_SHIFT_OFF[i];
        }
        else
        	data = MAP_BETA_BUF_LLR_SHIFT_OFF[i];   
        
        nim_reg_write(dev, R9C_DEMAP_BETA, &data, 1);
        data = 0x03;
        nim_reg_write(dev, R9C_DEMAP_BETA + 0x03, &data, 1);
    }


	// FEC use SPI output to TSO, use fast speed
	data = 0x10;
	nim_reg_write(dev, RAD_TSOUT_SYMB+1, &data, 1);
	data = 0x02;
	nim_reg_write(dev, RAD_TSOUT_SYMB, &data, 1);
	return ;
}

/*****************************************************************************
* INT32 nim_s3503_open(struct nim_device *dev)
* Description: S3501 open
*
* Arguments:
*  Parameter1: struct nim_device *dev
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_open(struct nim_device *dev)
{
	INT32 ret;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

	NIM_PRINTF("    Enter fuction nim_s3503_open\n");
	nim_s3503_set_acq_workmode(dev, NIM_OPTR_HW_OPEN);

	ret = nim_s3503_hw_check(dev);
	if (ret != SUCCESS)
		return ret;
	ret = nim_s3503_hw_init(dev);

	nim_s3503_after_reset_set_param(dev);

	nim_s3503_set_hbcd_timeout(dev, NIM_OPTR_HW_OPEN);

	nim_s3503_task_init(dev);

#ifdef CHANNEL_CHANGE_ASYNC
	if (priv->flag_id == OSAL_INVALID_ID)
		priv->flag_id = NIM_FLAG_CREATE(0);
#endif
	//NIM_PRINTF("    Leave fuction nim_s3503_open\n");
	return SUCCESS;
}

/*****************************************************************************
* INT32 nim_s3503_close(struct nim_device *dev)
* Description: S3501 close
*
* Arguments:
*  Parameter1: struct nim_device *dev
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_close(struct nim_device *dev)
{
	//UINT8  data,ver_data;

	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

	nim_s3503_set_demod_ctrl(dev, NIM_DEMOD_CTRL_0X90);

	nim_s3503_set_acq_workmode(dev, NIM_OPTR_HW_CLOSE);

	NIM_MUTEX_DELETE(priv->ul_status.nim_s3501_sema);

#ifdef CHANNEL_CHANGE_ASYNC
	NIM_FLAG_DEL(priv->flag_id);
#endif

	if(OSAL_E_OK!=osal_task_delete(priv->tsk_status.m_task_id))                   //Seiya add
	{
		AUTOSCAN_PRINTF("M3501 Task Delete Error Happenened!\n");
	}
	return SUCCESS;
}
/*****************************************************************************
* static INT32 nim_s3503_tuner_lock(struct nim_device *dev, UINT8 *tun_lock)
* Description: Get tuner lock status
*
* Arguments:
*  Parameter1: struct nim_device *dev
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_tuner_lock(struct nim_device *dev, UINT8 *tun_lock)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	//UINT8 data;

	/* Setup tuner */
	NIM_MUTEX_ENTER(priv);
	priv->nim_Tuner_Status(priv->tuner_id, tun_lock);
	NIM_MUTEX_LEAVE(priv);

	return SUCCESS;
}

/*****************************************************************************
* INT32 nim_s3503_ioctl(struct nim_device *dev, INT32 cmd, UINT32 param)
*
*  device input/output operation
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: INT32 cmd
*  Parameter3: UINT32 param
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_ioctl(struct nim_device *dev, INT32 cmd, UINT32 param)
{
	INT32 CRNum = 0;
	INT32 CURFreq = 0;
	INT32 step = 0;
	//UINT8 data;

	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	//NIM_PRINTF("  Enter fuction nim_s3503_ioctl\n");
	switch (cmd)
	{
	case NIM_DRIVER_READ_TUNER_STATUS:
		return nim_s3503_tuner_lock(dev, (UINT8 *) param);
	case NIM_DRIVER_READ_QPSK_STATUS:
		return nim_s3503_get_lock(dev, (UINT8 *) param);
	case NIM_DRIVER_READ_FEC_STATUS:
		break;
	case NIM_DRIVER_READ_QPSK_BER:
		return nim_s3503_get_BER(dev, (UINT32 *) param);
	case NIM_DRIVER_READ_VIT_BER:
		break;
	case NIM_DRIVER_READ_RSUB:
		return nim_s3503_get_PER(dev, (UINT32 *) param);
	case NIM_DRIVER_STOP_ATUOSCAN:
		priv->ul_status.s3501_autoscan_stop_flag = param;
		break;
	case NIM_DRIVER_GET_CR_NUM:
		CRNum = (INT32) nim_s3503_get_CRNum(dev);
		return CRNum;
	case NIM_DRIVER_GET_CUR_FREQ:
		switch (param)
		{
		case NIM_FREQ_RETURN_SET:
			return priv->ul_status.m_setting_freq;
		case NIM_FREQ_RETURN_REAL:
		default:
			CURFreq = (INT32) nim_s3503_get_CURFreq(dev);
			return CURFreq;
		}
	case NIM_DRIVER_FFT_PARA:
		nim_s3503_FFT_set_para(dev);
		break;
	case NIM_DRIVER_FFT:
		return nim_s3503_FFT(dev, param);
	case NIM_FFT_JUMP_STEP:
		step = 0;
		nim_s3503_get_tune_freq(dev, &step);
		return step;
	case NIM_DRIVER_SET_RESET_CALLBACK:
		priv->ul_status.m_pfn_reset_s3501 = (pfn_nim_reset_callback) param;
		break;
	case NIM_DRIVER_RESET_PRE_CHCHG:
		if (priv->ul_status.m_pfn_reset_s3501)
		{
			priv->ul_status.m_pfn_reset_s3501((priv->tuner_id + 1) << 16);
		}
		break;
	case NIM_DRIVER_ENABLE_DVBS2_HBCD:
		priv->ul_status.m_enable_dvbs2_hbcd_mode = param;
		nim_s3503_set_hbcd_timeout(dev, NIM_OPTR_IOCTL);
		break;
	case NIM_DRIVER_STOP_CHANSCAN:
		priv->ul_status.s3501_chanscan_stop_flag = param;
		break;
	case NIM_DRIVER_SET_BLSCAN_MODE:
		if(0 == param)
		   priv->blscan_mode = NIM_SCAN_FAST;
		else if(1 == param)
		   priv->blscan_mode = NIM_SCAN_SLOW;
		break;

    case NIM_DRIVER_SET_POLAR:
        return nim_s3503_set_polar(dev, (UINT8)param);
        break;
    case NIM_DRIVER_SET_12V:
        return nim_s3503_set_12v(dev, (UINT8)param);
        break;
    case NIM_DRIVER_GET_SYM:
        return nim_s3503_get_symbol_rate(dev, (UINT32 *)param);
        break;
    case NIM_DRIVER_GET_BER:
        return nim_s3503_get_BER(dev, (UINT32 *)param);
        break;
    case NIM_DRIVER_GET_AGC:
        return nim_s3503_get_AGC(dev, (UINT8 *)param);
        break;
    case NIM_TURNER_SET_STANDBY:
	 if (priv->nim_Tuner_Control != NULL)
	 {
	 	priv->nim_Tuner_Control(priv->tuner_id, NIM_TUNER_SET_STANDBY_CMD, 0);
	 }
	 break;
	default:
		break;
	}
	return SUCCESS;
}

/*****************************************************************************
* INT32 nim_s3503_set_polar(struct nim_device *dev, UINT8 polar)
* Description: S3501 set polarization
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8 pol
*
* Return Value: void
*****************************************************************************/
//#define REVERT_POLAR
static INT32 nim_s3503_set_polar(struct nim_device *dev, UINT8 polar)
{
	UINT8 data = 0;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	if (priv->ext_lnb_control)
		return priv->ext_lnb_control(priv->ext_lnb_id, LNB_CMD_SET_POLAR, (UINT32) polar);
	nim_reg_read(dev, R7C_DISEQC_CTRL, &data, 1);

	if ((priv->Tuner_Config_Data.QPSK_Config & M3501_POLAR_REVERT) == 0x00) //not exist H/V polarity revert.
	{
		if (NIM_PORLAR_HORIZONTAL == polar)
		{
			data &= 0xBF;
			NIM_PRINTF("nim_s3503_set_polar CR5C is 00\n");
		}
		else if (NIM_PORLAR_VERTICAL == polar)
		{
			data |= 0x40;
			NIM_PRINTF("nim_s3503_set_polar CR5C is 40\n");
		}
		else
		{
			NIM_PRINTF("nim_s3503_set_polar error\n");
			return ERR_FAILUE;
		}
	}
	else//exist H/V polarity revert.
	{
		if (NIM_PORLAR_HORIZONTAL == polar)
		{
			data |= 0x40;
			NIM_PRINTF("nim_s3503_set_polar CR5C is 40\n");
		}
		else if (NIM_PORLAR_VERTICAL == polar)
		{
			data &= 0xBF;
			NIM_PRINTF("nim_s3503_set_polar CR5C is 00\n");
		}
		else
		{
			NIM_PRINTF("nim_s3503_set_polar error\n");
			return ERR_FAILUE;
		}
	}

	nim_reg_write(dev, R7C_DISEQC_CTRL, &data, 1);
	return SUCCESS;
}

/*****************************************************************************
* static INT32 nim_s3503_set_12v(struct nim_device *dev, UINT8 flag)
* Description: S3501 set LNB votage 12V enable or not
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8 flag
*
* Return Value: SUCCESS
*****************************************************************************/
static INT32 nim_s3503_set_12v(struct nim_device *dev, UINT8 flag)
{
	return SUCCESS;
}


/*****************************************************************************
* static INT32 nim_s3503_get_bit_rate(struct nim_device *dev, UINT8 work_mode, UINT8 map_type, UINT8 code_rate, UINT32 Rs, UINT32 *bit_rate)
* Description: S3501 set LNB votage 12V enable or not
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8 flag
*
* Return Value: SUCCESS
*****************************************************************************/
static INT32 nim_s3503_get_bit_rate(struct nim_device *dev, UINT8 work_mode, UINT8 map_type, UINT8 code_rate, UINT32 Rs, UINT32 *bit_rate)
{
	UINT32 data;
	UINT32 temp;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

	if (work_mode != M3501_DVBS2_MODE) // DVBS mode
	{
		if (code_rate == 0)
			temp = (Rs * 2 * 1 + 1000) / 2000;
		else if (code_rate == 1)
			temp = (Rs * 2 * 2 + 1500) / 3000;
		else if (code_rate == 2)
			temp = (Rs * 2 * 3 + 2000) / 4000;
		else if (code_rate == 3)
			temp = (Rs * 2 * 5 + 3000) / 6000;
		else
			temp = (Rs * 2 * 7 + 4000) / 8000;

		if (temp > 254)
			data = 255;
		else
			data = temp + 1;	// add 1 M for margin
		*bit_rate = data;
		NIM_PRINTF("xxx dvbs bit_rate is %d \n", *bit_rate);
		return SUCCESS;
	}
	else	//DVBS2 mode
	{
		if (code_rate == 0)
			temp = (Rs * 1 + 2000) / 4000;
		else if (code_rate == 1)
			temp = (Rs * 1 + 1500) / 3000;
		else if (code_rate == 2)
			temp = (Rs * 2 + 2500) / 5000;
		else if (code_rate == 3)
			temp = (Rs * 1 + 1000) / 2000;
		else if (code_rate == 4)
			temp = (Rs * 3 + 2500) / 5000;
		else if (code_rate == 5)
			temp = (Rs * 2 + 1500) / 3000;
		else if (code_rate == 6)
			temp = (Rs * 3 + 2000) / 4000;
		else if (code_rate == 7)
			temp = (Rs * 4 + 2500) / 5000;
		else if (code_rate == 8)
			temp = (Rs * 5 + 3000) / 6000;
		else if (code_rate == 9)
			temp = (Rs * 8 + 4500) / 9000;
		else
			temp = (Rs * 9 + 5000) / 10000;

		if (map_type == 2)
			temp = temp * 2;
		else if (map_type == 3)
			temp = temp * 3;
		else if (map_type == 4)
			temp = temp * 4;
		else
		{
			NIM_PRINTF("Map type error: %02x \n", map_type);
		}

		if ((priv->Tuner_Config_Data.QPSK_Config & M3501_USE_188_MODE) == M3501_USE_188_MODE)
		{
			temp = temp;
		}
		else
		{
			temp = (temp * 204 + 94) / 188;
		}

		if (temp > 200)
			data = 200;
		else
			data = temp;
		NIM_PRINTF("Code rate is: %02x \n", code_rate);
		NIM_PRINTF("Map type is: %02x \n", map_type);

		data += 1; // Add 1M
		*bit_rate = data;
		NIM_PRINTF("xxx dvbs2 bit_rate is %d \n", *bit_rate);
		return SUCCESS;
	}
}

/*****************************************************************************
* static INT32 nim_s3503_open_ci_plus(struct nim_device *dev, UINT8 *ci_plus_flag)
* Description: S3501 set LNB votage 12V enable or not
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8 flag
*
* Return Value: SUCCESS
*****************************************************************************/
static INT32 nim_s3503_open_ci_plus(struct nim_device *dev, UINT8 *ci_plus_flag)
{
	UINT8 data;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

	// For CI plus test.
	data = 0x02;	// symbol period from reg, 2 cycle
	nim_reg_write(dev, RAD_TSOUT_SYMB, &data, 1);
	NIM_PRINTF("open ci plus enable REG_ad = %02x \n", data);

	nim_reg_read(dev, RAD_TSOUT_SYMB + 0x01, &data, 1);
	data = data | 0x80;    // enable symbol period from reg
	nim_reg_write(dev, RAD_TSOUT_SYMB + 0x01, &data, 1);

	nim_reg_read(dev, RDC_EQ_DBG_TS_CFG, &data, 1);
	data = data | 0xe0;
	nim_reg_write(dev, RDC_EQ_DBG_TS_CFG, &data, 1);

	nim_reg_read(dev, RDF_TS_OUT_DVBS2, &data, 1);
	data = (data & 0xfc) | 0x01;
	nim_reg_write(dev, RDF_TS_OUT_DVBS2, &data, 1);

	*ci_plus_flag = 1;

	return SUCCESS;
}

/*****************************************************************************
* static INT32 nim_s3503_get_phase_error(struct nim_device *dev, INT32 *phase_error)
* Description: S3501 set LNB votage 12V enable or not
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8 flag
*
* Return Value: SUCCESS
*****************************************************************************/
static INT32 nim_s3503_get_phase_error(struct nim_device *dev, INT32 *phase_error)
{
	UINT8 rdata = 0;
	UINT8 data = 0;

	nim_reg_read(dev, RC0_BIST_LDPC_REG + 4, &data, 1);
	if (data & 0x80)
	{
		data &= 0x7f;
		nim_reg_write(dev, RC0_BIST_LDPC_REG + 4, &data, 1);
	}
	nim_reg_read(dev, RC0_BIST_LDPC_REG, &data, 1);
	if ((data & 0x04) == 0)
	{
		nim_reg_read(dev, RC0_BIST_LDPC_REG + 5, &rdata, 1);
		data |= 0x04;
		nim_reg_write(dev, RC0_BIST_LDPC_REG, &data, 1);
		if (rdata & 0x80)
			*phase_error = rdata - 256;
		else
			*phase_error = rdata;   	// phase error is signed!!!
		NIM_PRINTF("phase error is %d\n", (*phase_error));
		return SUCCESS;  // means phase error measured.
	}
	else
	{
		*phase_error = 0;
		return ERR_FAILUE;  // means that phase error is not ready
	}
}


/*****************************************************************************
* static INT32 nim_s3503_cr_set_phase_noise(struct nim_device *dev)
* Description: S3501 set phase noise for OLD CR mode
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8 flag
*
* Return Value: SUCCESS
*****************************************************************************/
static INT32 nim_s3503_cr_set_phase_noise(struct nim_device *dev)
{
	return SUCCESS;
}


#define sys_ms_cnt (SYS_CPU_CLOCK/2000)

/*****************************************************************************
* static INT32 nim_s3503_waiting_channel_lock(struct nim_device *dev, UINT32 freq, UINT32 sym)
* Description: S3501 set polarization
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8 pol
*
* Return Value: void
*****************************************************************************/
static INT32 nim_s3503_waiting_channel_lock(struct nim_device *dev, UINT32 freq, UINT32 sym)
{
	UINT32 timeout, locktimes = 200;
	UINT32 tempFreq;
	UINT32 Rs;
	UINT32 starttime = 0;
	UINT32 endtime;
	UINT8 work_mode, map_type, iqswap_flag, roll_off, modcod;
	UINT8 intindex, intdata;
	UINT8 code_rate;
	UINT8 data;

	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	UINT8 channel_change_flag = 1; //bentao add for judge channel chang or soft_search in set_ts_mode
	timeout = 0;

	if (sym > 40000)
		locktimes = 204;
	else if (sym < 2000)
		locktimes = 2000;
	else if (sym < 4000)
		locktimes = 1604 - sym / 40;
	else if (sym < 6500)
		locktimes = 1004 - sym / 60;
	else
		locktimes = 604 - sym / 100;

		locktimes *= 3;

	while (priv->ul_status.s3501_chanscan_stop_flag == 0)
	{
		timeout ++ ;
		if (locktimes < timeout)					 // hardware timeout
		{
			priv->t_Param.phase_noise_detect_finish = 1;
			nim_s3503_interrupt_clear(dev);
			NIM_PRINTF("    timeout \n");
			priv->ul_status.s3501_chanscan_stop_flag = 0;
			priv->tsk_status.m_lock_flag = NIM_LOCK_STUS_SETTING;
			return ERR_FAILED;
		}

		nim_reg_read(dev, R04_STATUS, &intdata, 1);
		data = 0x3f;
		if ((intdata&0x3f) == data)  // if lock, get and print TP information
		{
			nim_s3503_reg_get_work_mode(dev, &work_mode);
			//NIM_PRINTF("            work_mode is %d\n", work_mode);
			switch(work_mode)
			{
				case 0 : {NIM_PRINTF("            work_mode is DVB-S \n"); break;}
				case 1 : {NIM_PRINTF("            work_mode is DVB-S2 \n"); break;}
				case 2 : {NIM_PRINTF("            work_mode is DVB-H8PSK \n"); break;}
			}

			priv->tsk_status.m_lock_flag = NIM_LOCK_STUS_CLEAR;
			priv->ul_status.m_CurFreq = tempFreq;
			priv->ul_status.s3501_chanscan_stop_flag = 0;

			// ------ Get information start
			tempFreq = freq;
			nim_s3503_reg_get_freq(dev, &tempFreq);
			NIM_PRINTF("            Freq is %d\n", (LNB_LOACL_FREQ - tempFreq));

			nim_s3503_reg_get_symbol_rate(dev, &Rs);
			NIM_PRINTF("            Rs is %d\n", Rs);

			nim_s3503_reg_get_code_rate(dev, &code_rate);
			if(0==work_mode)
			{
				switch(code_rate)
				{
					case 0 : {NIM_PRINTF("            code_rate is 1/2\n"); break;}
					case 1 : {NIM_PRINTF("            code_rate is 2/3\n"); break;}
					case 2 : {NIM_PRINTF("            code_rate is 3/4\n"); break;}
					case 3 : {NIM_PRINTF("            code_rate is 5/6\n"); break;}
					case 4 : {NIM_PRINTF("            code_rate wrong\n"); break;}
					case 5 : {NIM_PRINTF("            code_rate is 7/8\n"); break;}
				}

			}
			else if(1==work_mode)
			{
				switch(code_rate)
				{
					case 0 : {NIM_PRINTF("            code_rate is 1/4\n"); break;}
					case 1 : {NIM_PRINTF("            code_rate is 1/3\n"); break;}
					case 2 : {NIM_PRINTF("            code_rate is 2/5\n"); break;}
					case 3 : {NIM_PRINTF("            code_rate is 1/2\n"); break;}
					case 4 : {NIM_PRINTF("            code_rate is 3/5\n"); break;}
					case 5 : {NIM_PRINTF("            code_rate is 2/3\n"); break;}
					case 6 : {NIM_PRINTF("            code_rate is 3/4\n"); break;}
					case 7 : {NIM_PRINTF("            code_rate is 4/5\n"); break;}
					case 8 : {NIM_PRINTF("            code_rate is 5/6\n"); break;}
					case 9 : {NIM_PRINTF("            code_rate is 8/9\n"); break;}
					case 10 : {NIM_PRINTF("            code_rate is 9/10\n"); break;}
				}

			}

			if(1==work_mode)
			{
				nim_s3503_reg_get_roll_off(dev, &roll_off);
				switch(roll_off)
				{
					case 0 : {NIM_PRINTF("            roll_off is 0.35\n");break;};
					case 1 : {NIM_PRINTF("            roll_off is 0.25\n");break;};
					case 2 : {NIM_PRINTF("            roll_off is 0.20\n");break;};
					case 3 : {NIM_PRINTF("            roll_off is wrong\n");break;};
				}
			}
			if(1==work_mode)
			{
						nim_s3503_reg_get_modcod(dev, &modcod);
						if(modcod & 0x01)
							NIM_PRINTF("            Pilot on \n");
						else
                                          {
							NIM_PRINTF("            Pilot off \n");
                                           }
						modcod = modcod>>2;
						NIM_PRINTF("            Modcod is %d\n", modcod);
			}

			nim_s3503_reg_get_iqswap_flag(dev, &iqswap_flag);
			NIM_PRINTF("            iqswap_flag is %d\n", iqswap_flag);

			nim_s3503_reg_get_map_type(dev, &map_type);
			//NIM_PRINTF("            map_type is %d\n", map_type);
			if(1==work_mode)
			{
				switch(map_type)
				{
					case 0 : {NIM_PRINTF("            map_type is HBCD\n"); break;}
					case 1 : {NIM_PRINTF("            map_type is BPSK\n"); break;}
					case 2 : {NIM_PRINTF("            map_type is QPSK\n"); break;}
					case 3 : {NIM_PRINTF("            map_type is 8PSK\n"); break;}
					case 4 : {NIM_PRINTF("            map_type is 16APSK\n"); break;}
					case 5 : {NIM_PRINTF("            map_type is 32APSK\n"); break;}
				}
			}
			else
			{
				NIM_PRINTF("            map_type is QPSK\n");
			}

			// ------ Get information end

			if ((priv->ul_status.m_enable_dvbs2_hbcd_mode == 0) && ((map_type == 0) || (map_type == 5)))
			{
				NIM_PRINTF("            Demod Error: wrong map_type is %d\n", map_type);
			}
			else
			{
				NIM_PRINTF("        lock chanel \n");

				#ifdef NIM_S3501_ASCAN_TOOLS
					tmp_lock=0x01;
				#endif			
			
				priv->t_Param.phase_noise_detect_finish = 1;
				if ((work_mode == M3501_DVBS2_MODE) && (map_type == 3) && (priv->t_Param.t_phase_noise_detected == 0))
				{
					// S2, 8PSK
					if (code_rate == 4)
					{
						// coderate3/5
						priv->t_Param.t_snr_thre1 = 30;
						priv->t_Param.t_snr_thre2 = 45;
						priv->t_Param.t_snr_thre3 = 85;
					}
					else if ((code_rate == 5) || (code_rate == 6))
					{
						// coderate2/3,3/4
						priv->t_Param.t_snr_thre1 = 35;
						priv->t_Param.t_snr_thre2 = 55;
					}
					else if (code_rate == 7)
					{
						// coderate5/6
						priv->t_Param.t_snr_thre1 = 55;
						priv->t_Param.t_snr_thre2 = 65;
					}
					else if (code_rate == 8)
					{
						// coderate8/9
						priv->t_Param.t_snr_thre1 = 75;
					}
					else
					{
						// coderate9/10
						priv->t_Param.t_snr_thre1 = 80;
					}
				}

				if ((work_mode == M3501_DVBS2_MODE) && (map_type <= 3)) 	//only s2 need dynamic power
					priv->t_Param.t_dynamic_power_en = 1;

				/* Keep current frequency.*/
				priv->ul_status.m_CurFreq = tempFreq;
				nim_s3503_interrupt_clear(dev);
				priv->ul_status.s3501_chanscan_stop_flag = 0;
				return SUCCESS;
			}
		}
		else
		{
			if (priv->ul_status.s3501_chanscan_stop_flag)
			{
				priv->ul_status.s3501_chanscan_stop_flag = 0;
				priv->tsk_status.m_lock_flag = NIM_LOCK_STUS_SETTING;
				return ERR_FAILED;
			}
			comm_delay(200);
		}
	}

	priv->ul_status.s3501_chanscan_stop_flag = 0;
	return SUCCESS;
}
static  test_case = 1;
/*****************************************************************************
* static INT32 nim_s3503_channel_change(struct nim_device *dev, UINT32 freq, UINT32 sym, UINT8 fec)
* Description: S3501 set polarization
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8 pol
*
* Return Value: void
*****************************************************************************/
static INT32 nim_s3503_channel_change(struct nim_device *dev, UINT32 freq, UINT32 sym, UINT8 fec)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	UINT8 data = 0x10;
	UINT8 lock = 200;
	UINT8 low_sym;
	UINT8 channel_change_flag = 1; //bentao add for judge channel chang or soft_search in set_ts_mode

	//starttime = 0;
	NIM_PRINTF("    Enter Fuction nim_s3503_channel_change \n");
	NIM_PRINTF("    freq is %d\n", freq);
	NIM_PRINTF("    sym is %d\n", sym);
	NIM_PRINTF("    fec is %d\n", fec);

    AutoScan_or_ChannelChange=1;

	priv->t_Param.t_phase_noise_detected = 0;
	priv->t_Param.t_dynamic_power_en = 0;
	priv->t_Param.t_last_snr = -1;
	priv->t_Param.t_last_iter = -1;
	priv->t_Param.t_aver_snr = -1;
	priv->t_Param.t_snr_state = 0;
	priv->t_Param.t_snr_thre1 = 256;
	priv->t_Param.t_snr_thre2 = 256;
	priv->t_Param.t_snr_thre3 = 256;
	priv->t_Param.phase_noise_detect_finish = 0x00;
 // capture freq
//      nim_s3503_cap(dev, freq,  fft_energy_store,  sym);
//      nim_s3503_cap(dev, freq,  fft_energy_store,  0);
  //nim_s3503_adc2mem_entity( dev, 0, 0, 0,0x10000);
/*UINT32 dram_len = 0x10000;
UINT32 *dram_base_t=(UINT8 *) MALLOC(dram_len );
nim_s3503_adc2mem_cap(dev, freq, sym, *dram_base_t, dram_len);
free(dram_base_t);
*/


#ifdef CHANNEL_CHANGE_ASYNC
	UINT32 flag_ptn = 0;
	if (NIM_FLAG_WAIT(&flag_ptn, priv->flag_id, NIM_FLAG_CHN_CHG_START | NIM_FLAG_CHN_CHANGING, OSAL_TWF_ORW, 0) == OSAL_E_OK)
	{
		// channel chaning, stop the old changing first.
		priv->ul_status.s3501_chanscan_stop_flag = 1;
		//libc_printf("channel changing already, stop it first\n");
		comm_sleep(2); //sleep 2ms
	}
#endif
	priv->ul_status.phase_err_check_status = 0;
	priv->ul_status.s3501d_lock_status = NIM_LOCK_STUS_NORMAL;
	priv->ul_status.m_setting_freq = freq;

	//reset first
	nim_s3503_set_demod_ctrl(dev, NIM_DEMOD_CTRL_0X91);

	if(sym<44000)
		nim_s3503_set_dsp_clk (dev, 96);
	else
		nim_s3503_set_dsp_clk (dev, 135);

	if ((0 == freq) || (0 == sym))
		return SUCCESS;

	nim_s3503_sym_config(dev, sym);
	// time for channel change and sof search.
	nim_s3503_TR_CR_Setting(dev, NIM_OPTR_CHL_CHANGE);

	low_sym = sym < 6500 ? 1 : 0;   /* Symbol rate is less than 10M, low symbol rate */

	nim_s3503_freq_offset_set(dev, low_sym, &freq);

	//result = 200;
	if (priv->nim_Tuner_Control != NULL)
	{
		priv->nim_Tuner_Control(priv->tuner_id, freq, sym);
	}

	lock = 200;
	comm_sleep(1);
	if (priv->nim_Tuner_Status != NULL)
		priv->nim_Tuner_Status(priv->tuner_id, &lock);

	nim_s3503_set_adc(dev);

	nim_s3503_interrupt_mask_clean(dev);

	// hardware timeout setting
	nim_s3503_set_hw_timeout(dev, 0xff);

	// AGC1 setting
	nim_s3503_set_agc1(dev, low_sym, NIM_OPTR_CHL_CHANGE);

	// Set symbol rate
	nim_s3503_set_RS(dev, sym);

	// Set carry offset
	nim_s3503_freq_offset_reset(dev, low_sym);

	nim_s3503_cr_setting(dev, NIM_OPTR_CHL_CHANGE);
    
	nim_s3503_set_acq_workmode(dev, NIM_OPTR_CHL_CHANGE0);

	// set sweep range
	nim_s3503_set_FC_Search_Range(dev, NIM_OPTR_CHL_CHANGE, sym);
	nim_s3503_set_RS_Search_Range(dev, NIM_OPTR_CHL_CHANGE, sym);
	// LDPC parameter
	nim_s3503_fec_set_ldpc(dev, NIM_OPTR_CHL_CHANGE, 0x00, 0x01);
	// Carcy disable HBCD check, let time out. 2008-03-12
	nim_s3503_set_hbcd_timeout(dev, NIM_OPTR_CHL_CHANGE);

	nim_s3503_tso_dummy_on(dev);
	nim_s3503_tso_soft_cbr_off(dev);

//	comm_delay(10);

	nim_s3503_cr_adaptive_configure (dev, sym);

	nim_s3503_set_demod_ctrl(dev, NIM_DEMOD_CTRL_0X51);

/// re-initial NEW CR TAB
    nim_s3503_cr_new_modcod_table_init(dev,sym);

    nim_s3503_cr_new_adaptive_unlock_monitor(dev);
    nim_s3503_NframeStepTso_setting(dev,sym,0x01);
//nim_s3503_cr_ld_setting(dev);
#if defined CHANNEL_CHANGE_ASYNC && !defined NIM_S3501_ASCAN_TOOLS
	priv->cur_freq = freq;
	priv->cur_sym = sym;
	NIM_FLAG_SET(priv->flag_id, NIM_FLAG_CHN_CHG_START);
#else
	nim_s3503_waiting_channel_lock(dev, freq, sym);
#endif

	NIM_PRINTF("    Leave Fuction nim_s3503_channel_change \n");
	priv->ul_status.s3501_chanscan_stop_flag = 0;
	
	//UINT32  *dram_base_t;
       //dram_base_t=(UINT8 *) MALLOC(0x10000 );
       //nim_s3503_adc2mem_calculate_energy(dev,dram_base_t,0x10000);
       //comm_free(dram_base_t);

	return SUCCESS;
}


/*****************************************************************************
* void nim_s3503_interrupt_clear(struct nim_device *dev)
* Description: S3501 set polarization
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8 pol
*
* Return Value: void
*****************************************************************************/
static  void nim_s3503_interrupt_clear(struct nim_device *dev)
{
	UINT8 data;
	UINT8 rdata;
	//clear the int
	//CR02
	data = 0x00;
	nim_reg_write(dev, R02_IERR, &data, 1);
	nim_reg_write(dev, R04_STATUS, &data, 1);

	nim_reg_read(dev, R00_CTRL, &rdata, 1);
	data = (rdata | 0x10);
	nim_s3503_set_demod_ctrl(dev, data);

	//NIM_PRINTF("    enter nim_s3503_interrupt_clear\n");
}

/*****************************************************************************
* UINT32 nim_s3503_get_CURFreq(struct nim_device *dev)
* Description: S3501 set polarization
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8 pol
*
* Return Value: void
*****************************************************************************/
static UINT32 nim_s3503_get_CURFreq(struct nim_device *dev)
{
	return ((struct nim_s3501_private *) dev->priv)->ul_status.m_CurFreq;
}

/*****************************************************************************
* UINT8 nim_s3503_get_CRNum(struct nim_device *dev)
* Description: S3501 set polarization
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8 pol
*
* Return Value: void
*****************************************************************************/
static  UINT8 nim_s3503_get_CRNum(struct nim_device *dev)
{
	return ((struct nim_s3501_private *) (dev->priv))->ul_status.m_CRNum;
}

/*****************************************************************************
* void nim_s3503_FFT_set_para(struct nim_device *dev)
* Description: S3501 set polarization
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8 pol
*
* Return Value: void
*****************************************************************************/
static  void nim_s3503_FFT_set_para(struct nim_device *dev)
{
	return;
}

/*****************************************************************************
* INT32 nim_s3503_FFT(struct nim_device *dev, UINT32 startFreq)
* Description: S3501 set polarization
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8 pol
*
* Return Value: void
*****************************************************************************/
static INT32 nim_s3503_FFT(struct nim_device *dev, UINT32 startFreq)
{
	UINT32 freq = 0;
	UINT8 lock = 200;
	UINT32 cur_f, last_f, cur_rs, last_rs, ch_num,temp_swap;

	INT32 i = 0;

/**************** Get Current Time for Debug Convenient****************/
	struct nim_s3501_private *dev_priv;
	//date_time dt;
	//get_local_time(&dt);
	//AUTOSCAN_PRINTF("\nStep into nim_s3503_FFT:Blind Scan Current 90MHZ BW time %d:%d:%d\n",dt.hour,dt.min,dt.sec);

	dev_priv = (struct nim_s3501_private *)dev->priv;
	freq = startFreq;

	//clear interrupt for software search
	if (dev_priv->ul_status.s3501_autoscan_stop_flag)
	{
		NIM_PRINTF("    leave fuction nim_s3503_FFT\n");
		return SUCCESS;
	}

	dev_priv->nim_Tuner_Control(dev_priv->tuner_id, freq, 0);

	comm_delay(0xffff*4);
	if (dev_priv->nim_Tuner_Status != NULL)
		dev_priv->nim_Tuner_Status(dev_priv->tuner_id, &lock);

	dev_priv->ul_status.m_CRNum = 0;
	dev_priv->ul_status.m_StepFreq = nim_s3503_cap_fft_find_channel(dev, &startFreq);

    AUTOSCAN_PRINTF("\tCurrent Time Blind Scan Range: From  %dMHz to %dMHz  have find %d channels\n", startFreq - 45, startFreq + 45, dev_priv->ul_status.m_CRNum);
	for (i = 0; i < dev_priv->ul_status.m_CRNum; i++)
	{
		AUTOSCAN_PRINTF("\tTP -> %d. Freq = %d, Rs = %d\n", i, dev_priv->ul_status.m_Freq[i], dev_priv->ul_status.m_Rs[i]);
	}

//    if(NIM_SCAN_SLOW == dev_priv->blscan_mode)
	{
		// amy add for double check, avoid one TP detected as two
		if (dev_priv->ul_status.m_CRNum > 1)
		{
			ch_num = dev_priv->ul_status.m_CRNum;
			for (i = 1; i < dev_priv->ul_status.m_CRNum; i++)
			{
				cur_f = dev_priv->ul_status.m_Freq[i];
				last_f = dev_priv->ul_status.m_Freq[i-1];

				cur_rs = dev_priv->ul_status.m_Rs[i];
				last_rs = dev_priv->ul_status.m_Rs[i-1];

				if (cur_f-last_f < (cur_rs+last_rs)/2000)
				{
					cur_f = last_f + (cur_f-last_f)*cur_rs/(cur_rs+last_rs);
					cur_rs = last_rs + (cur_f-last_f)*2000;
					dev_priv->ul_status.m_Freq[ch_num] = cur_f;
					dev_priv->ul_status.m_Rs[ch_num] = cur_rs;
					ch_num ++;
					AUTOSCAN_PRINTF("\tError detected TP, modified to -> %d. Freq=%d, Rs=%d\n",ch_num,cur_f,cur_rs);
				}
			}
			if (dev_priv->ul_status.m_CRNum < ch_num){
				AUTOSCAN_PRINTF("current FFT result is:\n");
				for (i=0;i<1024;i=i+1)
					AUTOSCAN_PRINTF("%d\n",FFT_energy_1024[i]);
			}
		    dev_priv->ul_status.m_CRNum = ch_num;

	    }

		for (i = 0; i < dev_priv->ul_status.m_CRNum; i++)
		{
//			AUTOSCAN_PRINTF("\tAfter raw TP Modified,TP Distribution:TP -> %d. Freq = %d, Rs = %d\n", i, dev_priv->ul_status.m_Freq[i], dev_priv->ul_status.m_Rs[i]);
		}
	}

	return SUCCESS;
}


/*****************************************************************************
* INT32 nim_s3503_soft_search(struct nim_device *dev, UINT32 *est_rs, UINT32 *est_freq, INT32 delfreq)
* Description: S3501 set polarization
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8 pol
*
* Return Value: void
*****************************************************************************/
static  INT32 nim_s3503_soft_search(struct nim_device *dev, UINT32 *est_rs, UINT32 *est_freq, INT32 delfreq)
{
    UINT8 data, ver_data[2];
    UINT8 intindex;
    UINT8 intdata;
    UINT8 lock_monitor = 0;
    UINT8 modcod;
    UINT32 tempFreq, freq;
    UINT32 Rs, rs, rs_rev=0;
    UINT8 code_rate, map_type, work_mode;//ver_data,
    UINT32 temp;
    UINT32 timeout;
    UINT32 tr_lock_thr;
    UINT32 cr_lock_thr;
    UINT32 fs_lock_thr;
    UINT32 ck_lock_num;
    UINT32 tr_lock_num;
    UINT32 cr_lock_num;
    UINT8 low_sym = 0;
    UINT8 lock = 200;
    UINT32 hwtmout_cnt = 0;
    UINT8 level, quality, dcc_i, dcc_q;
    struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
    UINT32 tr_lock_flag = 0;
    UINT32 cr_lock_flag = 0;
    UINT32 loss_lock_cnt = 0;
    INT32 last_freq, last_rs, del_freq, del_rs; // from UINT32 to INT32 by russell
    UINT32 s2_lock_cnt = 0;
    UINT32 RS_Search_Range=0, RS_Search_Step=0;
    rs = *est_rs;
    freq = *est_freq;
    AUTOSCAN_PRINTF("       Try TP : Freq = %4d, RS = %5d, delfc = %6d:\n ",freq,rs,delfreq);
    //reset first
    nim_s3503_set_demod_ctrl(dev, NIM_DEMOD_CTRL_0X91);
    nim_reg_read(dev,R07_AGC1_CTRL+1, &data,1);
    data = data & 0x7f;
    nim_reg_write(dev, R07_AGC1_CTRL+1, &data, 1);

    if ((0 == freq) || (0 == rs))
    {
        return ERR_FAILED;
    }
    low_sym = 0;					// always use centre frequency
    nim_s3503_freq_offset_set(dev, low_sym, &freq);
    comm_delay(500);
    Rs=rs;
    
    if(rs<2500)
        tr_lock_thr = 10;
    else
        tr_lock_thr = 6;
    
    if(rs<=3000)
        cr_lock_thr = 30;
    else if(rs<10000)
        cr_lock_thr = 20;
    else
        cr_lock_thr = 15;
    
    fs_lock_thr = cr_lock_thr+10;
    if(Rs<44000)
        nim_s3503_set_dsp_clk (dev, 96);
    else
        nim_s3503_set_dsp_clk (dev, 135);
    if (priv->nim_Tuner_Control != NULL)
        priv->nim_Tuner_Control(priv->tuner_id, freq, Rs);
    if (priv->nim_Tuner_Status != NULL)
        priv->nim_Tuner_Status(priv->tuner_id, &lock);
    //NIM_PRINTF("Tuner lock = %d\n",lock);
    comm_delay(500);
    lock = 200;
    nim_s3503_interrupt_mask_clean(dev);
    data = 0xff;
    nim_s3503_set_hw_timeout(dev, data);
    nim_s3503_set_agc1(dev, low_sym, NIM_OPTR_SOFT_SEARCH);////CR07  AGC setting
    nim_s3503_set_RS(dev, rs);
    nim_s3503_freq_offset_reset1(dev, low_sym, delfreq);
    nim_s3503_set_FC_Search_Range(dev, NIM_OPTR_SOFT_SEARCH, rs);
    nim_s3503_set_RS_Search_Range(dev, NIM_OPTR_SOFT_SEARCH, rs);
    //nim_s3503_cr_adaptive_configure(dev, rs);  //// Seen add begin, copy from channel change
    nim_s3503_tso_soft_cbr_off(dev);
    nim_s3503_tso_dummy_on ( dev);
    nim_s3503_set_demod_ctrl(dev, NIM_DEMOD_CTRL_0X51);
    timeout = 0;
    lock_monitor = 0;
    hwtmout_cnt = 0;
    ck_lock_num = 0;
    tr_lock_num = 0;
    cr_lock_num = 0;
    last_freq = 0;
    last_rs = 0;
    while (1)
    {
        if (lock==0)
        {
            priv->nim_Tuner_Status(priv->tuner_id, &lock);
            if (lock==1)
            {
                NIM_PRINTF("Tuner lock = %d at timeout = %d\n",lock,timeout);
            }
        }
        timeout ++ ;
        if (100 < timeout)
        {
            nim_s3503_interrupt_clear(dev);
            AUTOSCAN_PRINTF("\tTimeout \n");
            return ERR_FAILED;
        }
        if (priv->ul_status.s3501_autoscan_stop_flag)
        {
            AUTOSCAN_PRINTF("\tleave fuction nim_s3503_soft_search\n");
            return SUCCESS;
        }
        comm_sleep(50);
        //get the status
        //nim_reg_read(dev, R64_RS_SEARCH, ver_data, 2);
        //RS_Search_Range= (ver_data[0]+((ver_data[1]&0x03)<<8))>>4;
        //RS_Search_Step=(ver_data[1]>>4)&(0x07);
        //NIM_PRINTF("        RS_Search_Range =  %d, RS_Search_Step=%d \n", RS_Search_Range,RS_Search_Step);
        //intindex=0;
        //nim_reg_read(dev, 0x0b, &intindex, 1);
        //NIM_PRINTF("        AGC1_GAIN  is %d \n", intindex);
        //nim_s3503_reg_get_symbol_rate(dev, &Rs);
        //tempFreq = freq;
        //nim_s3503_reg_get_freq(dev, &tempFreq);
        //NIM_PRINTF("        RS=%d  \n", Rs);
        
        intindex=0;
        nim_reg_read(dev, R04_STATUS, &intindex, 1);
        if (intindex&0x40)
            s2_lock_cnt ++;
        else
            s2_lock_cnt=0;
        NIM_PRINTF("        Lock status is 0x%x\n", intindex);
        
        if(intindex&0x18)//FS_LOCK or CR_lock
        {
            lock_monitor = lock_monitor | intindex;
            nim_s3503_reg_get_symbol_rate(dev, &Rs);
            tempFreq = freq;
            nim_s3503_reg_get_freq(dev, &tempFreq);
            nim_s3503_reg_get_work_mode(dev, &work_mode);
            del_freq = tempFreq - last_freq;
            if (del_freq < 0)
                del_freq = -del_freq;
                del_rs = Rs - last_rs;
            if (del_rs < 0)
                del_rs = -del_rs;
            if(del_freq<=2)
                cr_lock_num++;
            else
            {
                cr_lock_num = 0;
                last_freq = tempFreq;
                last_rs = Rs;
            }
            AUTOSCAN_PRINTF("       current lock Rs is %d,  Freq is %d at time %d\n",Rs, tempFreq,timeout);
            del_rs=rs_rev-Rs;
            if(del_rs<0)
                del_rs=-del_rs;
            if((Rs>=1000)&&(del_rs>=100))
                rs_rev=Rs;
            Rs=rs_rev;
            if ((work_mode==0) || (work_mode==1) || (s2_lock_cnt>4))
            {
                NIM_PRINTF("    path2:lock chanel \n");
                NIM_PRINTF("            Freq is %d\n", (LNB_LOACL_FREQ - tempFreq));
                priv->ul_status.m_CurFreq = tempFreq ;
                NIM_PRINTF("            Rs is %d\n", Rs);
                nim_s3503_reg_get_code_rate(dev, &code_rate);
                NIM_PRINTF("            code_rate is %d\n", code_rate);
                NIM_PRINTF("            work_mode is %d\n", work_mode);
                nim_s3503_reg_get_map_type(dev, &map_type);
                NIM_PRINTF("            map_type is %d\n", map_type);
                AUTOSCAN_PRINTF("\tLock freq %d Rs %d with del_Rs %d del_f %d \n",(LNB_LOACL_FREQ - tempFreq),Rs,Rs-rs,tempFreq-freq);
                AUTOSCAN_PRINTF("work_mode= %d, s2_lock_cnt= %d \n",work_mode,s2_lock_cnt);
                Final_Est_Freq=tempFreq;
                Final_Est_SymRate=Rs;
#ifdef NIM_S3501_ASCAN_TOOLS
                nim_s3501_ascan_add_tp(ASCAN_ADD_REAL_TP,0x00,tempFreq, Rs, tempFreq>1550?1:0);
#endif
                AUTOSCAN_PRINTF("\t timeout = %d\n",timeout);
                nim_s3503_interrupt_clear(dev);
                return SUCCESS;
            }
        }
        if((intindex&0x04) == 0x04)//TR_lock???
        {
            lock_monitor = lock_monitor | 0x04;
            tr_lock_num++;
            if (tr_lock_flag==0)
            {
                nim_s3503_reg_get_symbol_rate(dev, &Rs);
                NIM_PRINTF("        RS=%d \n", Rs);
                if(Rs<=1000)
                {
                    tr_lock_num--;
                }
                else
                {
                    tr_lock_flag = 1;
                    if(Rs<=2000)
                        cr_lock_thr = 35;////Yatai5: 12321/V/1500
                    else if(Rs<=3000)
                        cr_lock_thr = 30;
                    else if(Rs<10000)
                        cr_lock_thr = 20;
                    else
                        cr_lock_thr = 15;
                    fs_lock_thr = cr_lock_thr+10;
                    nim_s3503_set_demod_ctrl(dev, NIM_DEMOD_CTRL_0X91);
                    comm_delay(500);
                    if (priv->nim_Tuner_Control != NULL)
                        priv->nim_Tuner_Control(priv->tuner_id, freq, Rs);
                    if (priv->nim_Tuner_Status != NULL)
                        priv->nim_Tuner_Status(priv->tuner_id, &lock);
                    comm_delay(500);
                    lock = 200;
                    nim_s3503_set_agc1(dev, low_sym, NIM_OPTR_CHL_CHANGE);
                    nim_s3503_set_RS(dev, Rs);
                    nim_s3503_set_FC_Search_Range(dev, NIM_OPTR_SOFT_SEARCH, Rs);
                    nim_s3503_interrupt_clear(dev);
                    data = 0x00;
                    nim_reg_write(dev, R28_PL_TIMEOUT_BND,&data,1);
                    nim_reg_read(dev,R28_PL_TIMEOUT_BND+1,&data,1);
                    data &= 0xe0;
                    data |= 0x01;
                    nim_reg_write(dev,R28_PL_TIMEOUT_BND+1,&data,1);
                    nim_s3503_set_demod_ctrl(dev, NIM_DEMOD_CTRL_0X51);
                    tr_lock_thr = tr_lock_thr-2;
                    lock_monitor = 0;
                    hwtmout_cnt = 0;
                    ck_lock_num = 0;
                    tr_lock_num = 0;
                    cr_lock_num = 0;
                    rs_rev=Rs;
                    AUTOSCAN_PRINTF("Reset: freq = %d, Rs = %d at time %d\n",freq,Rs,timeout);
                    timeout = 0;
                }
            }
        }
        //AUTOSCAN_PRINTF("     lock_monitor is 0x%x\n", lock_monitor );
        if(tr_lock_thr == timeout)
        {
            if((lock_monitor&0xfc) == 0x00) // TR never lock
            {
                AUTOSCAN_PRINTF("        Fault TP, exit without TR lock \n");
                return ERR_FAILED;
            }
        }
        else if(cr_lock_thr == timeout)
        {
            if(((lock_monitor&0xf8) == 0x00) &  (tr_lock_num<5)) // TR  lock
            {
                AUTOSCAN_PRINTF("        Fault TP, exit without CR lock,  tr_lock_num %d\n",tr_lock_num);
                return ERR_FAILED;
            }
        }
        else if(fs_lock_thr == timeout)
        {
            if(((lock_monitor&0xf0) == 0x00) &  (cr_lock_num<5)) // CR  lock
            {
                AUTOSCAN_PRINTF("        Fault TP, exit without Frame lock, cr_lock_num %d\n",cr_lock_num);
                return ERR_FAILED;
            }
        }
        nim_reg_read(dev, R00_CTRL, &intindex, 1);
        if (0 == (intindex & 0x10))
        {
            nim_reg_read(dev, R02_IERR, &intdata, 1);
            AUTOSCAN_PRINTF("       Interrupt register is 0x%02x\n", intdata);
            if (0x04 == (intdata & 0x04))
            {
                AUTOSCAN_PRINTF("        Can not lock chanel \n");
                return ERR_FAILED;
            }
            if (0x20 == (intdata & 0x20))
            {
                AUTOSCAN_PRINTF("        CR loss lock  \n");
            }
            if (0 != (intdata & 0x02))
            {
                NIM_PRINTF("    path1:lock chanel \n");
                tempFreq = freq;
                nim_s3503_reg_get_freq(dev, &tempFreq);
                NIM_PRINTF("            Freq is %d\n", (LNB_LOACL_FREQ - tempFreq));
                priv->ul_status.m_CurFreq = tempFreq ;
                nim_s3503_reg_get_symbol_rate(dev, &Rs);
                NIM_PRINTF("            Rs is %d\n", Rs);
                del_rs=rs_rev-Rs;
                if(del_rs<0)
                    del_rs=-del_rs;
                if((Rs>=1000)&&(del_rs>=100))
                    rs_rev=Rs;
                Rs=rs_rev;
                nim_s3503_reg_get_code_rate(dev, &code_rate);
                NIM_PRINTF("            code_rate is %d\n", code_rate);
                nim_s3503_reg_get_work_mode(dev, &work_mode);
                NIM_PRINTF("            work_mode is %d\n", work_mode);
                nim_s3503_reg_get_map_type(dev, &map_type);
                NIM_PRINTF("            map_type is %d\n", map_type);
                nim_s3503_reg_get_modcod(dev, &modcod);
                if(modcod & 0x01)
                    NIM_PRINTF("            Pilot on \n");
                else
                {
                    NIM_PRINTF("            Pilot off \n");
                }
                modcod = modcod>>1;
                NIM_PRINTF("            Modcod is %x\n", modcod);
                Final_Est_Freq=tempFreq;
                Final_Est_SymRate=Rs;
#ifdef NIM_S3501_ASCAN_TOOLS
                nim_s3501_ascan_add_tp(ASCAN_ADD_REAL_TP,0x00,tempFreq, Rs, tempFreq>1550?1:0);
#endif
                AUTOSCAN_PRINTF("\tLock freq %d Rs %d with del_Rs %d del_f %d \n",(LNB_LOACL_FREQ - tempFreq),Rs,Rs-rs,tempFreq-freq);
                AUTOSCAN_PRINTF("\t timeout = %d\n",timeout);
                nim_s3503_interrupt_clear(dev);
                return SUCCESS;
            }
            nim_s3503_interrupt_clear(dev);
        }
    }
}

/*****************************************************************************
* INT32 nim_s3503_DiSEqC_initial (struct nim_device *dev)
*
*  defines DiSEqC operations
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT32 mode
*  Parameter3: UINT8* cmd
*  Parameter4: UINT8 cnt
*
* Return Value: void
*****************************************************************************/

static INT32 nim_s3503_DiSEqC_initial(struct nim_device *dev)
{
	UINT8 data;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	NIM_PRINTF("Diseqc initial \n");

    if(priv->ul_status.m_s3501_sub_type == NIM_S3503_SUB_ID)
    {
    // Set 22K clock ratio default 96MHz
	data = 0x60;
	nim_reg_write(dev, R90_DISEQC_CLK_RATIO, &data, 1);
     }

    // Diseqc time setting
    //4   DISEQC_HV_OEJ
    //3   DISEQC_OUT_OEJ
    //2   DISEQC_COMP_DIN_EN
    //1   DISEQC_ALIGN_EN
    //0   DISEQC_COMP_EN
    data = 0x02;
    nim_reg_write(dev, R114_DISEQC_TIME_SET, &data, 1);
// For C3503 only
    if(priv->ul_status.m_s3501_sub_type == NIM_C3503_SUB_ID)
    {
		// enable Diseqc auto select clock ratio.
		nim_reg_read (dev, RF1_DSP_CLK_CTRL, &data, 1);
		data = data | 0x80;
		nim_reg_write(dev, RF1_DSP_CLK_CTRL, &data, 1);
    }
    data = 0xff;
	nim_reg_write(dev, R8E_DISEQC_TIME + 0x01, &data, 1);    
#ifdef DISEQC_OUT_INVERT
	// invert diseqc out.
	nim_reg_read(dev, R90_DISEQC_CLK_RATIO+6, &data, 1);
	data = (data | 0x80);
	nim_reg_write(dev, R90_DISEQC_CLK_RATIO+6, &data, 1);
#endif
}


/*****************************************************************************
* INT32 nim_s3503_DiSEqC_operate(struct nim_device *dev, UINT32 mode, UINT8* cmd, UINT8 cnt)
*
*  defines DiSEqC operations
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT32 mode
*  Parameter3: UINT8* cmd
*  Parameter4: UINT8 cnt
*
* Return Value: void
*****************************************************************************/
static INT32 nim_s3503_DiSEqC_operate(struct nim_device *dev, UINT32 mode, UINT8 *cmd, UINT8 cnt)
{
	UINT8 data, temp;
	UINT16 timeout, timer;
	UINT8 i;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	NIM_PRINTF("mode = 0x%d\n", mode);

	switch (mode)
	{
	case NIM_DISEQC_MODE_22KOFF:
	case NIM_DISEQC_MODE_22KON:
		nim_reg_read(dev, R7C_DISEQC_CTRL, &data, 1);
		data = ((data & 0xF8) | mode);
		nim_reg_write(dev, R7C_DISEQC_CTRL, &data, 1);
		break;
	case NIM_DISEQC_MODE_BURST0:
		nim_reg_read(dev, R7C_DISEQC_CTRL, &data, 1);
		//tone burst 0
		temp = 0x02;
		data = ((data & 0xF8) | temp);
		nim_reg_write(dev, R7C_DISEQC_CTRL, &data, 1);
		comm_sleep(16);
		break;
	case NIM_DISEQC_MODE_BURST1:
		nim_reg_read(dev, R7C_DISEQC_CTRL, &data, 1);
		//tone bust 1
		temp = 0x03;
		data = ((data & 0xF8) | temp);
		nim_reg_write(dev, R7C_DISEQC_CTRL, &data, 1);
		comm_sleep(16);
		break;
	case NIM_DISEQC_MODE_BYTES:
        comm_sleep(DISEQC_DELAY);
        nim_reg_read(dev, R7C_DISEQC_CTRL, &data, 1);
        va_22k=(data & 0x41);      // get DISEQC_22k origianl value
        if(cnt>8)
        {
            NIM_PRINTF("\t\t NIM_ERROR : Diseqc cnt larger than 8: cnt = %d\n", cnt);
            return ERR_FAILED;
        }
        else
        {
            // close 22K and set TX byte number
            data = ((data & 0xc0) | ((cnt - 1)<<3));
            nim_reg_write(dev, R7C_DISEQC_CTRL, &data, 1);
        }
        //write the tx data, max 8 byte
        for (i = 0; i < cnt; i++)
        {
            nim_reg_write(dev, (i + 0x7E), cmd + i, 1);
        }
	 // remove clean interrupt, since reg7d is read only
        //write the control bits, start TX
        temp = 0x04;
        data = ((data & 0xF8) | temp);
        nim_reg_write(dev, R7C_DISEQC_CTRL, &data, 1);
        
         //wait for DISEQC_EVENT register cleared before every transmission
        comm_sleep(1);    
        //waiting for the send over
        timer = 0;
        timeout = 75 + 13 * cnt;
        while (timer < timeout)
        {
            nim_reg_read(dev, R7C_DISEQC_CTRL + 0x01, &data, 1);
            if ((0 != (data & 0x07))&&(timer>50))
            {
                break;
            }
            comm_sleep(10);
            timer += 10;
        }
        if (1 == (data & 0x07))
        {
            //resume DISEQC_22k origianl value
            nim_reg_read(dev, R7C_DISEQC_CTRL, &data, 1);
            data = ((data & 0xB8) | (va_22k));
            nim_reg_write(dev, R7C_DISEQC_CTRL, &data, 1);
            return  SUCCESS;
        }
        else
        {
            //resume DISEQC_22k origianl value
            nim_reg_read(dev, R7C_DISEQC_CTRL, &data, 1);            
            data = ((data & 0xB8) | (va_22k));
            nim_reg_write(dev, R7C_DISEQC_CTRL, &data, 1);
            return ERR_FAILED;
        }
        break;
    case NIM_DISEQC_MODE_BYTES_EXT_STEP1:
        comm_sleep(DISEQC_DELAY);
        nim_reg_read(dev, R7C_DISEQC_CTRL, &data, 1);
        va_22k=(data & 0x41);      // get DISEQC_22k origianl value
        if(cnt>8)
        {
            NIM_PRINTF("\t\t NIM_ERROR : Diseqc cnt larger than 8: cnt = %d\n", cnt);
            return ERR_FAILED;
        }
        else
        {
            // close 22K and set TX byte number
            data = ((data & 0xc0) | ((cnt - 1)<<3));
            nim_reg_write(dev, R7C_DISEQC_CTRL, &data, 1);
        }

        //write the data
        for (i = 0; i < cnt; i++)
        {
            nim_reg_write(dev, (i + 0x7E), cmd + i, 1);
        }
	 // remove clean interrupt, since reg7d is read only
        break;
    case NIM_DISEQC_MODE_BYTES_EXT_STEP2:
        //TX start : Send byte
        nim_reg_read(dev, R7C_DISEQC_CTRL, &data, 1);
        temp = 0x04;
        data = ((data & 0xF8) | temp);
        nim_reg_write(dev, R7C_DISEQC_CTRL, &data, 1);
         //wait for DISEQC_EVENT register cleared before every transmission
        comm_sleep(1);   
        //waiting for the send over
        timer = 0;
        timeout = 75 + 13 * cnt;
        while (timer < timeout)
        {
            nim_reg_read(dev, R7C_DISEQC_CTRL + 0x01, &data, 1);
            if ((0 != (data & 0x07))&&(timer>50))
            {
                break;
            }
            comm_sleep(10);
            timer += 10;
        }
        if (1 == (data & 0x07))
        {
            //resume DISEQC_22k origianl value
            nim_reg_read(dev, R7C_DISEQC_CTRL, &data, 1);            
            data = ((data & 0xB8) | (va_22k));
            nim_reg_write(dev, R7C_DISEQC_CTRL, &data, 1);
            
            return SUCCESS;
        }
        else
        {
            //resume DISEQC_22k origianl value
            nim_reg_read(dev, R7C_DISEQC_CTRL, &data, 1);            
            data = ((data & 0xB8) | (va_22k));
            nim_reg_write(dev, R7C_DISEQC_CTRL, &data, 1);
            
            return ERR_FAILED;
        }
        break;
	case NIM_DISEQC_MODE_ENVELOP_ON:
		{
			nim_reg_read(dev, R24_MATCH_FILTER, &data, 1);
			data |= 0x01;
			nim_reg_write(dev, R24_MATCH_FILTER, &data, 1);
		}
		break;
	case NIM_DISEQC_MODE_ENVELOP_OFF:
		{
			nim_reg_read(dev, R24_MATCH_FILTER, &data, 1);
			data &= 0xFE;
			nim_reg_write(dev, R24_MATCH_FILTER, &data, 1);
		}
		break;
	default :
		break;
	}
	return SUCCESS;
}

/*****************************************************************************
* INT32 nim_s3503_DiSEqC2X_operate(struct nim_device *dev, UINT32 mode, UINT8* cmd, UINT8 cnt, \
*   							UINT8 *rt_value, UINT8 *rt_cnt)
*
*  defines DiSEqC 2.X operations
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT32 mode
*  Parameter3: UINT8* cmd
*  Parameter4: UINT8 cnt
*  Parameter5: UINT8 *rt_value
*  Parameter6: UINT8 *rt_cnt
*
* Return Value: Operation result.
*****************************************************************************/
static INT32 nim_s3503_DiSEqC2X_operate(struct nim_device *dev, UINT32 mode, UINT8 *cmd, UINT8 cnt, UINT8 *rt_value, UINT8 *rt_cnt)
{
    INT32 result;
    UINT8 data, temp;
    UINT16 timeout, timer;
    UINT8 i;

    switch (mode)
    {
    case NIM_DISEQC_MODE_BYTES:
        //write the data to send buffer
        if(cnt>8)
        {
            NIM_PRINTF("\t\t NIM_ERROR : Diseqc cnt larger than 8: cnt = %d\n", cnt);
            return ERR_FAILED;
        }
        for (i = 0; i < cnt; i++)
        {
            data = cmd[i];
            nim_reg_write(dev, (i + R7C_DISEQC_CTRL + 0x02), &data, 1);
        }

        //set diseqc data counter
        temp = cnt - 1;
        nim_reg_read(dev, R7C_DISEQC_CTRL, &data, 1);
        va_22k=(data & 0x41);      // get DISEQC_22k origianl value
        data = ((data & 0x47) | (temp << 3));
        nim_reg_write(dev, R7C_DISEQC_CTRL, &data, 1);

        //enable diseqc interrupt mask event bit.
        nim_reg_read(dev, R03_IMASK, &data, 1);
        data |= 0x80;
        nim_reg_write(dev, R03_IMASK, &data, 1);

        //clear co-responding diseqc interrupt event bit.
        nim_reg_read(dev, R02_IERR, &data, 1);
        data &= 0x7f;
        nim_reg_write(dev, R02_IERR, &data, 1);

        //write the control bits, need reply
        nim_reg_read(dev, R7C_DISEQC_CTRL, &data, 1);
        temp = 0x84;
        data = ((data & 0x78) | temp);
        nim_reg_write(dev, R7C_DISEQC_CTRL, &data, 1);
         //wait for DISEQC_EVENT register cleared before every transmission
        comm_sleep(1); 

        //waiting for the send over
        timer = 0;
        timeout = 75 + 13 * cnt + 200; 
        data = 0;

        //check diseqc interrupt state.
        while (timer < timeout)
        {
            nim_reg_read(dev, R02_IERR, &data, 1);
            if (0x80 == (data & 0x80)) 
            {
                break;
            }
            comm_sleep(10);
            timer += 1;
        }

        //init value for error happens.
        result = ERR_FAILUE;
        rt_value[0] = DISEQC2X_ERR_NO_REPLY;
        *rt_cnt = 0;
        if (0x80 == (data & 0x80)) 
        {
            nim_reg_read(dev, R7C_DISEQC_CTRL + 0x01, &data, 1);

            switch (data & 0x07)
            {
            case 1:
                *rt_cnt = (UINT8) ((data >> 4) & 0x0f);
                if (*rt_cnt > 0)
                {
                    for (i = 0; i < *rt_cnt; i++)
                    {
                        nim_reg_read(dev, (i + R86_DISEQC_RDATA), (rt_value + i), 1);
                    }
                    result = SUCCESS;
                }

                break;

            case 2:
                rt_value[0] = DISEQC2X_ERR_NO_REPLY;
                break;
            case 3:
                rt_value[0] = DISEQC2X_ERR_REPLY_PARITY;
                break;
            case 4:
                rt_value[0] = DISEQC2X_ERR_REPLY_UNKNOWN;
                break;
            case 5:
                rt_value[0] = DISEQC2X_ERR_REPLY_BUF_FUL;
                break;
            default:
                rt_value[0] = DISEQC2X_ERR_NO_REPLY;
                break;
            }
        }

        //set 22k and polarity by origianl value; other-values are not care.
        nim_reg_read(dev, R7C_DISEQC_CTRL, &data, 1);
	    data = (data&0xb8) | va_22k;
        nim_reg_write(dev, R7C_DISEQC_CTRL, &data, 1);

        return result;

    default :
        break;
    }

	comm_sleep(1000);

	return SUCCESS;
}


/*****************************************************************************
* INT32 nim_s3503_get_lock(struct nim_device *dev, UINT8 *lock)
*
*  Read FEC lock status
*
*Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: BOOL *fec_lock
*
*Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_get_lock(struct nim_device *dev, UINT8 *lock)
{
	UINT8 data;
	UINT8 h8psk_lock;
	INT32 freq_offset;
	//UINT32  flgptn;

	comm_delay(150);
	nim_reg_read(dev, R04_STATUS, &data, 1);

	if ((data & 0x80) == 0x80)
		h8psk_lock = 1;
	else
		h8psk_lock = 0;
	if (h8psk_lock & ((data & 0x2f) == 0x2f))
	{
		*lock = 1;
	}
	else if ((data & 0x3f) == 0x3f)
	{
		*lock = 1;
	}
	else
	{
		*lock = 0;
	}
	comm_delay(150);

	return SUCCESS;
}

/*****************************************************************************
* INT32 nim_s3503_get_freq(struct nim_device *dev, UINT32 *freq)
* Read S3501 frequence
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16 *sym_rate 		: Symbol rate in kHz
*
* Return Value: void
*****************************************************************************/
static INT32 nim_s3503_get_freq(struct nim_device *dev, UINT32 *freq)
{
	nim_s3503_reg_get_freq(dev, freq);
	return SUCCESS;
}

/*****************************************************************************
* INT32 nim_s3503_get_symbol_rate(struct nim_device *dev, UINT32 *sym_rate)
* Read S3501 symbol rate
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16 *sym_rate 		: Symbol rate in kHz
*
* Return Value: void
*****************************************************************************/
static INT32 nim_s3503_get_symbol_rate(struct nim_device *dev, UINT32 *sym_rate)
{
	nim_s3503_reg_get_symbol_rate(dev, sym_rate);
	return SUCCESS;
}

/*****************************************************************************
* INT32 nim_s3503_get_code_rate(struct nim_device *dev, UINT8* code_rate)
* Description: Read S3501 code rate
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT8* code_rate
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_get_code_rate(struct nim_device *dev, UINT8 *code_rate)
{
	nim_s3503_reg_get_code_rate(dev, code_rate);
	return SUCCESS;
}

static UINT32 Log10Times100_L( UINT32 x)
{
   static const UINT8 scale=15;
   static const UINT8 indexWidth=5;
   /*
   log2lut[n] = (1<<scale) * 200 * log2( 1.0 + ( (1.0/(1<<INDEXWIDTH)) * n ))
   0 <= n < ((1<<INDEXWIDTH)+1)
   */

   static const UINT32 log2lut[] = {
      0, 290941,  573196,  847269,1113620, 1372674, 1624818, 
      1870412, 2109788, 2343253, 2571091, 2793569,3010931, 
      3223408, 3431216, 3634553, 3833610, 4028562, 4219576, 
      4406807, 4590402, 4770499, 4947231, 5120719, 5291081, 
      5458428, 5622864, 5784489, 5943398,  6099680, 6253421, 
      6404702,  6553600  };
	  
   UINT8  i = 0;
   UINT32 y = 0;
   UINT32 d = 0;
   UINT32 k = 0;
   UINT32 r = 0;

   if (x==0) return (0);

   /* Scale x (normalize) */
   /* computing y in log(x/y) = log(x) - log(y) */
   if ( (x & (((UINT32)(-1))<<(scale+1)) ) == 0 )
   {
      for (k = scale; k>0 ; k--)
      {
        if (x & (((UINT32)1)<<scale)) break;
        x <<= 1;
      }
   } else {
      for (k = scale; k<31 ; k++)
      {
        if ((x & (((UINT32)(-1))<<(scale+1)))==0) break;
        x >>= 1;
      }
   }
   /*
     Now x has binary point between bit[scale] and bit[scale-1]
     and 1.0 <= x < 2.0 */

   /* correction for divison: log(x) = log(x/y)+log(y) */
   y = k * ( ( ((UINT32)1) << scale ) * 200 );

   /* remove integer part */
   x &= ((((UINT32)1) << scale)-1);
   /* get index */
   i = (UINT8) (x >> (scale -indexWidth));
   /* compute delta (x-a) */
   d = x & ((((UINT32)1) << (scale-indexWidth))-1);
   /* compute log, multiplication ( d* (.. )) must be within range ! */
   y += log2lut[i] + (( d*( log2lut[i+1]-log2lut[i] ))>>(scale-indexWidth));
   /* Conver to log10() */
   y /= 108853; /* (log2(10) << scale) */
   r = (y>>1);
   /* rounding */
   if (y&((UINT32)1)) r++;

   return (r);

}
/*****************************************************************************
* INT32 nim_s3503_get_MER(struct nim_device *dev, UINT32 *mer)
* Description: Ger MER
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT32 *mer
*
* Return Value: UINT32
*****************************************************************************/

static INT32 nim_s3503_get_MER(struct nim_device *dev, UINT32 *mer)
{
    UINT8 data, data_in_i=0, data_in_q=0, data_out_i=0,data_out_q=0,map_type;
    UINT8 rdata[4];
    UINT32 i;
    UINT32 err_sum;
    UINT32 mer_tmp;

    #define NIM_MER_ACC_LEN 512
    #define NIM_MER_AVG_LEN 10
    #define NIM_MER_STA_LEN 4

    nim_reg_read(dev,R04_STATUS,&data,1);
    if (data&0x08)
    { // CR lock
        nim_reg_read(dev,R69_RPT_CARRIER+2,&data,1);
        map_type = data>>5;
        NIM_PRINTF("map_type = %d\n",map_type);
        err_sum = 0;
        if ((map_type==2)||(map_type==3)||(map_type==4)||(map_type==5))
            {  
            if(va_mer_window < NIM_MER_STA_LEN)
            {
                for (i=0;i<NIM_MER_ACC_LEN;i++)
                {
                    data = 0x01;
                    nim_reg_write(dev, R11C_MAP_IN_I, &data, 1);
                    comm_sleep(10);
                    nim_reg_read(dev, R11C_MAP_IN_I, rdata, 4);
                    if (rdata[0]&0x80)
                        data_in_i = 256-rdata[0];
                    else
                        data_in_i = rdata[0];
                    if (rdata[1]&0x80)
                        data_in_q = 256-rdata[1];
                    else
                        data_in_q = rdata[1];
                    if (rdata[2]&0x80)
                        data_out_i = 256-rdata[2];
                    else
                        data_out_i = rdata[2];
                    if (rdata[3]&0x80)
                        data_out_q = 256-rdata[3];
                    else
                        data_out_q = rdata[3];                 
                    err_sum = err_sum + (data_out_i-data_in_i)*(data_out_i-data_in_i) + (data_out_q-data_in_q)*(data_out_q-data_in_q);
                }
                va_mer = va_mer + err_sum;
                va_mer_window++;
                mer_tmp = err_sum/NIM_MER_ACC_LEN;
            }
            else
            {
                for (i=0;i<NIM_MER_AVG_LEN;i++)
                {
                    data = 0x01;
                    nim_reg_write(dev, R11C_MAP_IN_I, &data, 1);
                    comm_sleep(10);
                    nim_reg_read(dev, R11C_MAP_IN_I, rdata, 4);
                    if (rdata[0]&0x80)
                        data_in_i = 256-rdata[0];
                    else
                        data_in_i = rdata[0];
                    if (rdata[1]&0x80)
                        data_in_q = 256-rdata[1];
                    else
                        data_in_q = rdata[1];
                    if (rdata[2]&0x80)
                        data_out_i = 256-rdata[2];
                    else
                        data_out_i = rdata[2];
                    if (rdata[3]&0x80)
                        data_out_q = 256-rdata[3];
                    else
                        data_out_q = rdata[3];
                    err_sum = err_sum + (data_out_i-data_in_i)*(data_out_i-data_in_i) + (data_out_q-data_in_q)*(data_out_q-data_in_q);
                }
                va_mer = va_mer + err_sum/NIM_MER_AVG_LEN - va_mer/(NIM_MER_ACC_LEN*NIM_MER_STA_LEN);
                mer_tmp = va_mer/(NIM_MER_ACC_LEN*NIM_MER_STA_LEN);
            }
        }
        else // other modu type do not support
        {
            *mer = 0;
            NIM_PRINTF("map_type = %d, not supported\n",map_type);
            return ERR_FAILUE;
        }
    }
    else
    {
        NIM_PRINTF("cr unlock, data=%02x\n",data);      
        *mer = 0;
         va_mer = 0;
         va_mer_window = 0;
        return ERR_FAILUE;
    }
    if (mer_tmp > 1681)
        mer_tmp = 1681;
        mer_tmp = 323-Log10Times100_L(mer_tmp);
    if (mer_tmp>255)
        *mer = 255;
    else
        *mer = mer_tmp;
    return SUCCESS;
 }
/*****************************************************************************
* INT32 nim_s3503_get_AGC(struct nim_device *dev, UINT8 *agc)
*
*  This function will access the NIM to determine the AGC feedback value
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* agc
*
* Return Value: INT32
*****************************************************************************/
// get signal intensity

static INT32 nim_s3503_get_AGC(struct nim_device *dev, UINT8 *agc)
{
	UINT8 data;//, temp;
    UINT32 s_sum; 
    int k,n1,n2;
    static int j=0;
    static UINT8   s_data[15];  
    static UINT8   s_agc=0x00; 
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

	if (priv->Tuner_Config_Data.QPSK_Config & M3501_SIGNAL_DISPLAY_LIN)
	{
		nim_reg_read(dev, R04_STATUS, &data, 1);
		if (data & 0x01)
		{
			// AGC1 lock
			nim_reg_read(dev, R0A_AGC1_LCK_CMD + 0x01, &data, 1);  // read AGC1 gain
			if (data > 0x7f)
				*agc = data - 0x80;
			else
				*agc = data + 0x80;

		}
		else
			*agc = 0;
	}
	else
	{
		//CR0B
		nim_reg_read(dev, R07_AGC1_CTRL + 0x04, &data, 1);
		data = 255 - data;

		if (0x40 <= data)
			data -= 0x40;
		else if ((0x20 <= data) || (0x40 > data))
			data -= 0x20;
		else
			data -= 0;

		data /= 2;
		data += 16;
		*agc = (UINT8) data;
	}
#ifdef AGC_FILTER

     #define    s_filter_len  4  //even is better.
	if(*agc==0)
		j=0;
	if (j==(s_filter_len-1)) 
	{      
		for(k=0;k<=(s_filter_len-1);k++)
		{
			s_sum=s_sum+s_data[k];
		}
		*agc=s_sum/s_filter_len;
		n1=s_sum-(*agc)*s_filter_len;
		if(n1>=(s_filter_len/2))
			n1=1;
		else
			n1=0;
		*agc=*agc+n1;          
		s_agc=*agc;
		j=j+1;
	}
      else if (j==s_filter_len)
	{
		n1=(s_agc*(s_filter_len-1))/s_filter_len;
		n1=(s_agc*(s_filter_len-1))-n1*s_filter_len;
		n2=*agc/s_filter_len;
		n2=*agc-n2*s_filter_len;
		n2=n1+n2;
		if(n2>=(3*(s_filter_len/2)))
			n1=2;
		else if((n2<(3*(s_filter_len/2)))&&(n2>=(s_filter_len/2)))
			n1=1;
		else
		       n1=0;          
		*agc=(s_agc*(s_filter_len-1))/s_filter_len+*agc/s_filter_len+n1;
		s_agc=*agc;
	}
      else 
	{
		s_data[j]=*agc;
		*agc=*agc;
		j=j+1;
	}   
#endif 
	return SUCCESS;
}


/*****************************************************************************
* INT32 nim_s3503_get_SNR(struct nim_device *dev, UINT8 *snr)
*
* This function returns an approximate estimation of the SNR from the NIM
*  The Eb No is calculated using the SNR from the NIM, using the formula:
*     Eb ~     13312- M_SNR_H
*     -- =    ----------------  dB.
*     NO		   683
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_get_SNR(struct nim_device *dev, UINT8 *snr)
{

	UINT8 data;
       UINT16 snr_db = 0;  
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
  
        nim_s3503_get_snr_db(dev,&snr_db);
        snr_db=snr_db/10;      

        nim_reg_read(dev, R04_STATUS, &data, 1);
        if (0x3F == (data&0x3F))        // demod lock
        {
            if(snr_db>=150)
                *snr=90;
            else if(snr_db<120)
            {
                  *snr=snr_db/4;                                    
             }
            else
            {
                 *snr=(snr_db-120)*2+30;
            }
         }
         else    // demod unlock
         {
            *snr=10;
         }
        
        
	return SUCCESS;
}


/*
static INT32 nim_s3503_get_SNR(struct nim_device *dev, UINT8 *snr)
{
	//UINT8 work_mode;//, map_type;
	UINT8 lock; //coderate,
	//UINT32  Rs;
	UINT8 data,min,max;
	UINT32 tdata, iter_num,sym_rate,s_sum; //ber, per,
	int i, total_iter, sum,k,m;
    static int j=0;
    static UINT8   s_data[15];      
    static UINT8   average=0x00; 
    static UINT8   s_snr=0x00;  
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

	if (priv->Tuner_Config_Data.QPSK_Config & M3501_SIGNAL_DISPLAY_LIN)
	{
#define    TDATA_SUM_LIN 6
		nim_reg_read(dev, R04_STATUS, &data, 1);
		if (data & 0x08)
		{
			// CR lock
			sum = 0;
			total_iter = 0;
			for (i = 0; i < TDATA_SUM_LIN; i++)
			{
				nim_reg_read(dev, R45_CR_LCK_DETECT + 0x01, &data, 1);
				tdata = data << 8;
				nim_reg_read(dev, R45_CR_LCK_DETECT, &data, 1);
				tdata |= data;

				if (tdata & 0x8000)
					tdata = 0x10000 - tdata;

				nim_s3503_get_LDPC(dev, &iter_num);
				total_iter += iter_num;
				tdata >>= 5;
				sum += tdata;
			}
			sum /= TDATA_SUM_LIN;
			total_iter /= TDATA_SUM_LIN;
			sum *= 3;
			sum /= 5;
			if (sum > 255)
				sum = 255;

			if (priv->t_Param.t_last_snr == -1)
			{
				*snr = sum;
				priv->t_Param.t_last_snr = *snr;
			}
			else
			{
				if (total_iter == priv->t_Param.t_last_iter)
				{
					*snr = priv->t_Param.t_last_snr;
					if (sum > priv->t_Param.t_last_snr)
						priv->t_Param.t_last_snr ++;
					else if (sum < priv->t_Param.t_last_snr)
						priv->t_Param.t_last_snr --;
				}
				else if ((total_iter > priv->t_Param.t_last_iter) && (sum < priv->t_Param.t_last_snr))
				{
					*snr = sum;
					priv->t_Param.t_last_snr = sum;
				}
				else if ((total_iter < priv->t_Param.t_last_iter) && (sum > priv->t_Param.t_last_snr))
				{
					*snr = sum;
					priv->t_Param.t_last_snr = sum;
				}
				else
				{
					*snr = priv->t_Param.t_last_snr;
				}
			}
			priv->t_Param.t_last_iter = total_iter;
		}
		else
		{
			// CR unlock
			*snr = 0;
			priv->t_Param.t_last_snr = -1;
			priv->t_Param.t_last_iter = -1;
		}
	}
	else
	{
#define    TDATA_START 7
#define    TDATA_SUM 4

		tdata = 0;
		for (i = 0; i < TDATA_SUM; i++)
		{
			data = snr_tab[nim_s3503_get_SNR_index(dev)];
			tdata += data;
		}
		tdata /= TDATA_SUM;
		//CR04
		nim_reg_read(dev, R04_STATUS, &data, 1);
		if ((0x3F == data) | (0x7f == data) | (0xaf == data))
		{
		}
		else
		{
#if (SIGNAL_INDICATOR == 3)
			//To have linear signal indicator change between lock and unlock per Hicway's request
			//--Michael Xie 2005/8/17
			tdata = 0;
			if (0x01 == (data & 0x01)) //agc1
				tdata += 2;

			if (0x02 == (data & 0x02)) //agc2
				tdata += 10;

			if (0x04 == (data & 0x04)) //cr
				tdata += 16;

			if (0x08 == (data & 0x08)) //tr
				tdata += 16;

			if (0x10 == (data & 0x10)) //frame sync
				tdata += 20;

			if (0x20 == (data & 0x20))
				tdata += 26;
			if (0x40 == (data & 0x40))
				tdata += 26;

			if (0x80 == (data & 0x80))
				tdata += 26;
#else
			//tdata /= 2;
			tdata = TDATA_START;
			if (0x01 == (data & 0x01))
				tdata += 1;

			if (0x02 == (data & 0x02))
				tdata += 3;

			if (0x04 == (data & 0x04))
				tdata += 3;

			if (0x08 == (data & 0x08))
				tdata += 2;

			if (0x10 == (data & 0x10))
				tdata += 2;

			if (0x20 == (data & 0x20))
				tdata += 2;

			if (0x40 == (data & 0x40))
				tdata += 2;

			if (0x80 == (data & 0x80))
				tdata += 2;
#endif
		}
		*snr = tdata / 2;
	}

	if (priv->t_Param.t_aver_snr == -1)
	{
		priv->t_Param.t_aver_snr = (*snr);
	}
	else
	{
		priv->t_Param.t_aver_snr += (((*snr) - priv->t_Param.t_aver_snr) >> 2);
	}


#ifdef SNR_FILTER

    if (((*snr>average)&&(*snr-average>=5))||((*snr<average)&&(average-*snr>=5))) 
    {          
        s_data[j]=*snr;
        *snr=(*snr>average) ? (average+1):( average-1);
        j=j+1;
        if(j==3)
        {
            for(k = 0; k <= 2; k++)
            {
            if(s_data[k+1]>=s_data[k])
            {
               max=s_data[k+1];
               min=s_data[k];
            }
            else
            {
                max=s_data[k];
                min=s_data[k+1];
            }                       
            }
            average=(s_data[0]+s_data[1]+s_data[2]+s_data[3]-max-min)/2;
            j=0;
            }
    }
    else if (((*snr>=average)&&(*snr-average<=2))||((*snr<average)&&(average-*snr<=2))) 
    {
        *snr=average;
        j=0;
    }
    else 
    {
        *snr=(*snr>average) ? (average+1):( average-1);
        j=0;
    } 

#endif

//	if (priv->t_Param.t_dynamic_power_en)
//		nim_s3503_set_dynamic_power(dev, (*snr));

	return SUCCESS;
}
*/
 /*****************************************************************************
 * INT32 nim_s3503_check_BER(struct nim_device *dev, UINT32 *RsUbc)
 * Get bit error ratio(10E-5)
 *
 *  Arguments:
 *  Parameter1: struct nim_device *dev
 *  Parameter2: UINT16* RsUbc
 *
 * Return Value: INT32
 *****************************************************************************/
 static INT32 nim_s3503_check_BER(struct nim_device *dev, UINT32 *RsUbc)
 {
     UINT8 data;
     UINT8 work_mode;
     UINT8 ber_data[2];
     UINT32 u32ber_data[2];
     UINT32 uber_data;
     UINT32 i;    
 
     #define ber_dvbs_beta 100   
     #define ber_dvbs2_beta 100      
     
     struct nim_s3503_private *priv = (struct nim_s3503_private *) dev->priv;
 
     nim_reg_read(dev, R04_STATUS, &data, 1);
     if(0x3f != (data&0x3f))
     {
         va_ber = 0;
         va_ber_window = 0;
         *RsUbc = 0xffff;
         NIM_PRINTF("----NIM_WARNING: FEC unlock, can not get BER\n");
         return SUCCESS;
     }
     else
     {
         nim_s3503_reg_get_work_mode(dev, &work_mode);
         
         if(0 == work_mode) // DVBS 
         {
             if(va_ber_window<ber_dvbs_beta)
            {
                 for (i=0;i<ber_dvbs_beta;i++)
                {
                     nim_reg_read(dev, R54_VITERBI_FRAME_SYNC+1, ber_data, 2);
                     u32ber_data[0] = (UINT32) ber_data[0];
                     u32ber_data[1] = (UINT32) (ber_data[1]&0x0f);
                     u32ber_data[1] <<= 8;
                     uber_data = u32ber_data[1] + u32ber_data[0];                  
                     va_ber = va_ber + uber_data;
                     va_ber_window++;                   
                }
                *RsUbc = (va_ber*100)/ber_dvbs_beta;  //10*RsUbc = 108*(va_ber*1000000)/(ber_dvbs_beta*10000); 
             }
           else
           {
                 nim_reg_read(dev, R54_VITERBI_FRAME_SYNC+1, ber_data, 2);
                 u32ber_data[0] = (UINT32) ber_data[0];
                 u32ber_data[1] = (UINT32) (ber_data[1]&0x0f);
                 u32ber_data[1] <<= 8;
                 uber_data = u32ber_data[1] + u32ber_data[0];
                 va_ber = va_ber + uber_data - (va_ber/ber_dvbs_beta); 
                 *RsUbc = (va_ber*100)/ber_dvbs_beta;  //10*RsUbc = 108*(va_ber*1000000)/(ber_dvbs_beta*10000)          
           }         
         }
         else // DVBS2 
         {
            if(va_ber_window<ber_dvbs2_beta)
            {
                 for (i=0;i<ber_dvbs2_beta;i++)
                {
                 nim_reg_read(dev, RD3_BER_REG + 0x01, ber_data, 2);
                 u32ber_data[0] = (UINT32) ber_data[0];
                 u32ber_data[1] = (UINT32) ber_data[1];
                 u32ber_data[1] <<= 8;
                 uber_data = u32ber_data[1] + u32ber_data[0];                 
                 va_ber = va_ber + uber_data;
                 va_ber_window++;
                }
               *RsUbc = (va_ber*10000)/(ber_dvbs2_beta*648);//10*RsUbc =10*(va_ber*100000)/(ber_dvbs2_beta*64800)
             }
           else
           {
                 nim_reg_read(dev, RD3_BER_REG + 0x01, ber_data, 2);
                 u32ber_data[0] = (UINT32) ber_data[0];
                 u32ber_data[1] = (UINT32) ber_data[1];
                 u32ber_data[1] <<= 8;
                 uber_data = u32ber_data[1] + u32ber_data[0];
                 va_ber = va_ber + uber_data - (va_ber/ber_dvbs2_beta); 
                 *RsUbc = (va_ber*10000)/(ber_dvbs2_beta*648);//10*RsUbc =10*(va_ber*100000)/(ber_dvbs2_beta*64800)             
           }         
         }
 
         return SUCCESS;
     }
 }


/*****************************************************************************
* INT32 nim_s3503_get_BER(struct nim_device *dev, UINT32 *RsUbc)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_get_BER(struct nim_device *dev, UINT32 *RsUbc)
{
	UINT8 data;
	UINT8 ber_data[3];
	UINT32 u32ber_data[3];
	UINT32 uber_data;

	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	//CR78
	nim_reg_read(dev, R76_BIT_ERR + 0x02, &data, 1);
	if (0x00 == (0x80 & data))
	{
		//  	NIM_PRINTF( "CR78= %x\n", data);
		//CR76
		nim_reg_read(dev, R76_BIT_ERR, &ber_data[0], 1);
		u32ber_data[0] = (UINT32) ber_data[0];
		//CR77
		nim_reg_read(dev, R76_BIT_ERR + 0x01, &ber_data[1], 1);
		u32ber_data[1] = (UINT32) ber_data[1];
		u32ber_data[1] <<= 8;
		//CR78
		nim_reg_read(dev, R76_BIT_ERR + 0x02, &ber_data[2], 1);
		u32ber_data[2] = (UINT32) ber_data[2];
		u32ber_data[2] <<= 16;

		uber_data = u32ber_data[2] + u32ber_data[1] + u32ber_data[0];

		uber_data *= 100;
		uber_data /= 1632;
		*RsUbc = uber_data;
		priv->ul_status.old_ber = uber_data;
		//CR78
		data = 0x80;
		nim_reg_write(dev, R76_BIT_ERR + 0x02, &data, 1);
	}
	else
	{
		*RsUbc = priv->ul_status.old_ber;
	}

	return SUCCESS;
}

/*****************************************************************************
* INT32 nim_s3503_set_dynamic_power(struct nim_device *dev, UINT32 *RsUbc)
* Get bit error ratio
*
* Arguments:
* Parameter1:
* Key word: power_ctrl
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_set_dynamic_power(struct nim_device *dev, UINT8 snr)
{
	UINT8 coderate;
	UINT32 ber;
	static UINT32 ber_sum = 0;  // store the continuous ber
	static UINT32 last_ber_sum = 0;
	static UINT32 cur_ber_sum = 0;
	static UINT32 ber_thres = 0x180;
	static UINT8 cur_max_iter = 50; // static variable can not auto reset at channel change???
	static UINT8 snr_bak = 0;
	static UINT8 last_max_iter = 50;
	static int cnt3 = 0;

	if (cnt3 >= 3)
	{
		last_ber_sum = cur_ber_sum;
		cur_ber_sum = ber_sum;
		cnt3 = 0;
		ber_sum = 0;
	}
	nim_s3503_get_BER(dev, &ber);
	nim_s3503_reg_get_code_rate(dev, &coderate);
	ber_sum += ber;
	cnt3 ++;
	if (coderate < 0x04)	  // 1/4 rate
		ber_thres = 0x120;
	else
		ber_thres = 0x70;
	if (cur_max_iter == 50)
	{
		if (ber_sum >= ber_thres)
		{
			if (snr > snr_bak)
				snr_bak = snr;
			cur_max_iter -= 15;
		}
	}
	else if (cur_max_iter < 50)
	{
		if (((cur_ber_sum + 0x80) < last_ber_sum) || (snr > (snr_bak + 2)))
		{
			cur_max_iter += 15;
			snr_bak = 0;
			cnt3 = 0;
			ber_sum = 0;
			last_ber_sum = 0;
			cur_ber_sum = 0;
		}
		else if (ber_sum > 3 * ber_thres)
		{
			cur_max_iter -= 15;
			if ((coderate < 0x04) && (cur_max_iter < 35))
				cur_max_iter = 35;
			else if (cur_max_iter < 20)
				cur_max_iter = 20;
		}
	}

	if (cur_max_iter != last_max_iter)
	{
		NIM_PRINTF("----change cur_max_iter to %d----\n\n", cur_max_iter);
		nim_reg_write(dev, R57_LDPC_CTRL, &cur_max_iter, 1);
		last_max_iter = cur_max_iter;
	}
	return SUCCESS;
}


/*****************************************************************************
* INT32 nim_s3503_get_PER(struct nim_device *dev, UINT32 *RsUbc)
* Get packet error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_get_PER(struct nim_device *dev, UINT32 *RsUbc)
{
	UINT8 per[2];
	UINT16 percount;
	UINT8 data,verdata;
	static UINT8 flag0=1,flag1=0;
	static UINT32 cur_sym=0,last_sym=0;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

	*RsUbc=1010;
	nim_reg_read(dev, R04_STATUS, &data, 1);
	if (0x00 != (0x20 & data))
	{
		nim_reg_read(dev, R79_PKT_ERR + 0x01, &per[1], 1);
		per[1] = per[1] & 0x7f;
		nim_reg_read(dev, R79_PKT_ERR, &per[0], 1);
		percount = (UINT16) (per[1] * 256 + per[0]);
		*RsUbc = (UINT32) percount;
		NIM_PRINTF("current PER is  %d\n", percount);

		nim_reg_read(dev, R70_CAP_REG + 0x01, &data, 1);
		data=0x7f&data;
		nim_reg_write(dev, R70_CAP_REG + 0x01, &data, 1);
		comm_delay(10);
		nim_reg_read(dev, R70_CAP_REG + 0x01, &data, 1);
		data=0x80|data;
		nim_reg_write(dev, R70_CAP_REG + 0x01, &data, 1);

		return SUCCESS;
	}
	else
	{
		return ERR_PARA;
	}
}

/*****************************************************************************
* INT32 nim_s3503_get_LDPC(struct nim_device *dev, UINT32 *RsUbc)
* Get LDPC average iteration number
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_get_LDPC(struct nim_device *dev, UINT32 *RsUbc)
{
	UINT8 data;
	//UINT8   ite_num;
	//struct nim_s3501_private* priv = (struct nim_s3501_private  *)dev->priv;

	// read single LDPC iteration number
	nim_reg_read(dev, RAA_S2_FEC_ITER, &data, 1);
	*RsUbc = (UINT32) data;
	return SUCCESS;
}
/*****************************************************************************
* static INT32 nim_s3503_get_LDPC_iter_cnt(struct nim_device *dev, UINT16 *iter_cnt)
* Description: get ldpc iter counter 
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16 *iter_cnt, it is 10 bits width
*
* Return Value: INT32
*****************************************************************************/

static INT32 nim_s3503_get_LDPC_iter_cnt(struct nim_device *dev, UINT16 *iter_cnt)
{
	UINT8 data[2];
	// read LDPC iteration number, maybe once, maybe the max, according to reg_crc1[3]
	nim_reg_read(dev, RAA_S2_FEC_ITER, &data, 2);
    data[1] &= 0x03;
	*iter_cnt = (UINT16)(data[1]*256 + data[0]);
	return SUCCESS;
}

/*****************************************************************************
* 
static INT32 nim_s3503_set_LDPC_iter_cnt_record_last(struct nim_device *dev)
* Description: to record the last ldpc iter times
*
* Arguments:
*  Parameter1: struct nim_device *dev*  
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_set_LDPC_iter_cnt_record_last(struct nim_device *dev)
{
   UINT8 data;
   // read LDPC iteration number, maybe once, maybe the max, according to reg_crc1[3]
   nim_reg_read(dev, RC1_DVBS2_FEC_LDPC, &data, 1);
    data &= 0xf7;
   nim_reg_write(dev, RC1_DVBS2_FEC_LDPC, &data, 1);
   return SUCCESS;
}

/*****************************************************************************
* 

static INT32 nim_s3503_set_LDPC_iter_cnt_record_max(struct nim_device *dev)
* Description: to record the max ldpc iter times
*
* Arguments:
*  Parameter1: struct nim_device *dev*  
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_set_LDPC_iter_cnt_record_max(struct nim_device *dev)
{
   UINT8 data;
   // read LDPC iteration number, maybe once, maybe the max, according to reg_crc1[3]
   nim_reg_read(dev, RC1_DVBS2_FEC_LDPC, &data, 1);
    data |= 0x08;
   nim_reg_write(dev, RC1_DVBS2_FEC_LDPC, &data, 1);
   return SUCCESS;
}

/*****************************************************************************
* INT32 nim_s3503_channel_search(struct nim_device *dev, UINT32 CRNum );
* Description: S3501 channel blind searching operation
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT32 freq  			: Frequence
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_channel_search(struct nim_device *dev, UINT32 CRNum)
{
    UINT32 freq,freq0,freq1;
    INT32 k = 0;
    INT32 delfreq = 0,delfreq0=0;
    UINT32 sym;
    struct nim_s3501_private *dev_priv;
    dev_priv = (struct nim_s3501_private *)dev->priv;
    NIM_PRINTF("ENTER nim_s3503_channel_search: TP is %d\n", CRNum);
    
    freq = dev_priv->ul_status.m_Freq[CRNum];
    sym = dev_priv->ul_status.m_Rs[CRNum];
    
    delfreq = freq % 1024;
    freq = freq>>10;
    if(delfreq>512)
    {
        delfreq=delfreq-1024;
        freq=freq+1;
    }
    dev_priv->ul_status.m_CurFreq = freq;
    AUTOSCAN_PRINTF("ENTER nim_s3503_channel_search: TP -> %d. Freq=%d, Rs=%d\n", CRNum, freq, sym);
    if (SUCCESS == nim_s3503_soft_search(dev, &dev_priv->ul_status.m_Rs[CRNum], &freq, delfreq))
        return SUCCESS;
    else if((freq<=1846)&&(freq>=1845)&&(sym<=3000)&&(sym>=1500))/////Yatai5:12446/V/1537
    {
        AUTOSCAN_PRINTF("*************Try_again*************\n");
        if(delfreq<0)
        {
            freq0=freq;
            delfreq0=0;
        }
        else if(delfreq<400)
        {
            freq0=freq;
            delfreq0=0;
        }
        else
        {
            freq0=freq+1;
            delfreq0=0;
        }
        if (SUCCESS == nim_s3503_soft_search(dev, &dev_priv->ul_status.m_Rs[CRNum], &freq, delfreq))
            return SUCCESS;
        else if (SUCCESS == nim_s3503_soft_search(dev, &dev_priv->ul_status.m_Rs[CRNum], &freq0, delfreq0))
            return SUCCESS;
    }

#if 0
    if(NIM_SCAN_SLOW == dev_priv->blscan_mode)
    {
        if ((sym<5000) && (sym>3000))
        {
            for (k=0;k<2;k++)
            {
                switch(k)
                {
                    case 0:
                                freq = dev_priv->ul_status.m_Freq[CRNum]-1024;
                                delfreq = freq % 1024;
                                freq = freq>>10;
                                break;
                    case 1:
                                freq = dev_priv->ul_status.m_Freq[CRNum]+1024;
                                delfreq = freq % 1024;
                                freq = freq>>10;
                                break;
                }
                if (SUCCESS == nim_s3503_soft_search(dev, &dev_priv->ul_status.m_Rs[CRNum], &freq, delfreq))
                    return SUCCESS;
            }
        }
    }
#endif

    return ERR_FAILUE;
}

static  INT32 nim_s3503_reg_get_freq(struct nim_device *dev, UINT32 *freq)
{
	INT32 freq_off;
	UINT8 data[3];
	UINT32 sample_rate;
	UINT32 tdata;
	UINT32 temp;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	temp = 0;
        nim_reg_read(dev, R69_RPT_CARRIER, data, 3);
        tdata = (data[0]&0xff)  + ((data[1]&0xff) <<8);
        if ((data[2] & 0x01) == 1)
            temp = (tdata ^ 0xffff) + 1;
        else
            temp = tdata & 0xffff;
        nim_s3503_get_dsp_clk(dev, &sample_rate);
        if ((data[2] & 0x01) == 1)
            freq_off = 0 - nim_s3503_multu64div(temp, sample_rate, 92160000);
        else
            freq_off = nim_s3503_multu64div(temp, sample_rate, 92160000);
        *freq += freq_off;
	return SUCCESS;
}

/*****************************************************************************
* INT32 nim_s3503_reg_get_code_rate(struct nim_device *dev, UINT8 *code_rate)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static  INT32 nim_s3503_reg_get_code_rate(struct nim_device *dev, UINT8 *code_rate)
{
	UINT8 data;
	//  NIM_PRINTF("Enter Fuction nim_s3503_reg_get_code_rate \n");
	nim_reg_read(dev, R69_RPT_CARRIER + 0x02, &data, 1);
	*code_rate = ((data >> 1) & 0x0f);
	return SUCCESS;

	//  Code rate list
	//  for DVBS:
	//  	0x0:	1/2,
	//  	0x1:	2/3,
	//  	0x2:	3/4,
	//  	0x3:	5/6,
	//  	0x4:	6/7,
	//  	0x5:	7/8.
	//  For DVBS2 :
	//  	0x0:	1/4 ,
	//  	0x1:	1/3 ,
	//  	0x2:	2/5 ,
	//  	0x3:	1/2 ,
	//  	0x4:	3/5 ,
	//  	0x5:	2/3 ,
	//  	0x6:	3/4 ,
	//  	0x7:	4/5 ,
	//  	0x8:	5/6 ,
	//  	0x9:	8/9 ,
	//  	0xa:	9/10.
}

//  Carcy add ldpc_code information .
/*****************************************************************************
* static INT32 nim_s3503_reg_get_map_type(struct nim_device *dev, UINT8 *map_type)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_reg_get_map_type(struct nim_device *dev, UINT8 *map_type)
{
	UINT8 data;
	//  NIM_PRINTF("Enter Fuction nim_s3503_reg_get_map_type \n");
	nim_reg_read(dev, R69_RPT_CARRIER + 0x02, &data, 1);
	*map_type = ((data >> 5) & 0x07);
	return SUCCESS;

	//  Map type:
	//  	0x0:	HBCD.
	//  	0x1:	BPSK
	//  	0x2:	QPSK
	//  	0x3:	8PSK
	//  	0x4:	16APSK
	//  	0x5:	32APSK
}

/*****************************************************************************
* static INT32 nim_s3503_reg_get_work_mode(struct nim_device *dev, UINT8 *work_mode)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_reg_get_work_mode(struct nim_device *dev, UINT8 *work_mode)
{
	UINT8 data;
	//  NIM_PRINTF("Enter Fuction nim_s3503_reg_get_work_mode \n");
	nim_reg_read(dev, R68_WORK_MODE, &data, 1);
	*work_mode = data & 0x03;
	return SUCCESS;

	//  Work Mode
	//  	0x0:	DVB-S
	//  	0x1:	DVB-S2
	//  	0x2:	DVB-S2 HBC
}

/*****************************************************************************
* static INT32 nim_s3503_reg_get_iqswap_flag(struct nim_device *dev, UINT8 *iqswap_flag)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_reg_get_iqswap_flag(struct nim_device *dev, UINT8 *iqswap_flag)
{
	UINT8 data;
	//  NIM_PRINTF("Enter Fuction nim_s3503_reg_get_iqswap_flag \n");
	nim_reg_read(dev, R6C_RPT_SYM_RATE + 0x02, &data, 1);
	*iqswap_flag = ((data >> 4) & 0x01);
	return SUCCESS;
}

/*****************************************************************************
* static INT32 nim_s3503_reg_get_roll_off(struct nim_device *dev, UINT8 *roll_off)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_reg_get_roll_off(struct nim_device *dev, UINT8 *roll_off)
{
	UINT8 data;
	//  NIM_PRINTF("Enter Fuction nim_s3503_reg_get_roll_off \n");
	nim_reg_read(dev, R6C_RPT_SYM_RATE + 0x02, &data, 1);
	*roll_off = ((data >> 5) & 0x03);
	return SUCCESS;

	//  DVBS2 Roll off report
	//  	0x0:	0.35
	//  	0x1:	0.25
	//  	0x2:	0.20
	//  	0x3:	Reserved
}

/*****************************************************************************
* static INT32 nim_s3503_get_dsp_clk(struct nim_device *dev, UINT8 *sample_rate)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_get_dsp_clk(struct nim_device *dev, UINT32 *sample_rate)
{
	UINT8 data;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	//  NIM_PRINTF("Enter Fuction nim_s3503_reg_get_modcode \n");

	nim_reg_read(dev, RF1_DSP_CLK_CTRL, &data, 1);
	data = data & 0x03;
	// bit[1:0] dsp clk sel: // 00: 135m, 01:96m, 10:112m
	if(0 == data)
		*sample_rate =135000;  ////uint is KHz
	else if(1 == data)
		*sample_rate =96430;  ////uint is KHz
	else if(2 == data)
		*sample_rate =112500;  ////uint is KHz

	return SUCCESS;
}

/*****************************************************************************
* static INT32 nim_s3503_set_dsp_clk (struct nim_device *dev, UINT8 clk_sel)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_set_dsp_clk (struct nim_device *dev, UINT8 clk_sel)
{
	UINT8 data;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	//  NIM_PRINTF("Enter Fuction nim_s3503_reg_get_modcode \n");

    if(priv->ul_status.m_s3501_sub_type == NIM_S3503_SUB_ID)
    {
	data = clk_sel & 0xff;
	nim_reg_write(dev, R90_DISEQC_CLK_RATIO, &data, 1);
    }
	nim_reg_read(dev, RF1_DSP_CLK_CTRL, &data, 1);
	data = data & 0xfc;
	// bit[1:0] dsp clk sel: // 00: 135m, 01:96m
    if(96 == clk_sel)
		data = data | (UINT8)(1) ;
	else if(135 == clk_sel)
		data = data | (UINT8)(0) ;
	else
        NIM_PRINTF(" set dsp clock error!");
        
	nim_reg_write(dev, RF1_DSP_CLK_CTRL, &data, 1);

	return SUCCESS;
}

/*****************************************************************************
* static INT32 nim_s3503_cr_adaptive_initial (struct nim_device *dev)
*
*
*  Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_cr_adaptive_initial (struct nim_device *dev)
{
	UINT8 data;

	#ifdef SW_ADPT_CR
		// Just for debug now, should depends on MODCOD
		data = 0xc3;
		nim_reg_write(dev, R0E_ADPT_CR_CTRL, &data, 1); // enable SNR estimation
		data = 0x9e;
		nim_reg_write(dev, R0E_ADPT_CR_CTRL, &data, 1); // Bypass Adpt ForceOldCR
		nim_reg_read(dev, RE0_PPLL_CTRL, &data, 1);
		data |= 0x08;
		nim_reg_write(dev, RE0_PPLL_CTRL, &data, 1); // force old CR, just for debug now
	#endif

	#ifdef HW_ADPT_CR

		nim_s3503_cr_tab_init(dev);
		//Bypass Setting: All use CR adaptive table
		data = 0x81;
		nim_reg_write(dev, R0E_ADPT_CR_CTRL, &data, 1);

		#ifdef HW_ADPT_CR_MONITOR
			data = 0xe6; // enable hw adpt CR report, also enable always update to regfile, latter need review
			nim_reg_write(dev, R0E_ADPT_CR_CTRL, &data, 1);
		#endif
	#endif
	
	return SUCCESS;
}

/*****************************************************************************
* static INT32 nim_s3503_cr_adaptive_configure (struct nim_device *dev)
*
*
*  Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_cr_adaptive_configure (struct nim_device *dev, UINT32 sym)
{
	UINT8 data;
	UINT8 TabID;
	UINT32 TabVal,TabValTemp;
	UINT8 DatArray[2];

#ifdef SW_ADPT_CR
	snr_initial_en = 1;
#endif // SW_ADPT_CR

#ifdef HW_ADPT_CR
	NIM_PRINTF("            nim m3501c close dummy for dvbs \n");

	// To circumvent the symbol rate 13M problem
	/*  TAB_ID=15, CellID = 2
        WIDE_2 |  Reserved  |<------8PSK POFF-------->|  S2_QPSK |        |
                            |9/10 8/9 5/6 3/4 2/3 3/5 |PON POFF  | DVBS
        0x002 :             |0    0   0   0   0   0   |0   1     | 0        */

	// config ON/OFF Table of WIDE_2
	data = 0xe1; // CR Tab init en
	nim_reg_write(dev, R0E_ADPT_CR_CTRL, &data, 1);

	data = 0xf0 | 2; // TAB_ID | CellID
	nim_reg_write(dev, R9D_RPT_DEMAP_BETA, &data, 1);
	if(sym<=10000) // enable wider CR when S2 QPSK Rs<=10M
		DatArray[0] = 0x02;
	else
		DatArray[0] = 0x00;
	DatArray[1] = 0x80;
	nim_reg_write(dev, R11_DCC_OF_I, DatArray, 2);
	// End of to circumvent the symbol rate 13M problem

	// PRS=8,IRS=0x12 for 8PSK pilot off Rs<3M
	if(sym<=5000)
		TabVal = 0x10600;
	else if((sym>5000)&&(sym<17000))//for pn_astraf.fcf 20M symbol rate performance worse than C3501C 20121204
	//	TabVal = CR_PARA_8PSK_others[TAB_SIZE-1];
		TabVal = 0x10700;
	else		
		TabVal = 0x10800;
	TabValTemp = (TabVal & 0x7c)<<7;
    TabVal = (TabVal>>8) |TabValTemp | 0x8000;  // to HW format;
	DatArray[0] = (UINT8)(TabVal & 0x0ff);
	DatArray[1] = (UINT8)((TabVal>>8) & 0x0ff);

	for(TabID=4; TabID<=6; TabID++) 
	{
		data = (TabID<<4) | (PSK8_TAB_SIZE-1);//12.5
		nim_reg_write(dev, R9D_RPT_DEMAP_BETA, &data, 1);
		nim_reg_write(dev, R11_DCC_OF_I, DatArray, 2);

		data = (TabID<<4) | (PSK8_TAB_SIZE-2);//12.0
		nim_reg_write(dev, R9D_RPT_DEMAP_BETA, &data, 1);
		nim_reg_write(dev, R11_DCC_OF_I, DatArray, 2);

		data = (TabID<<4) | (PSK8_TAB_SIZE-3);//11.5
		nim_reg_write(dev, R9D_RPT_DEMAP_BETA, &data, 1);
		nim_reg_write(dev, R11_DCC_OF_I, DatArray, 2);
       }
	if(sym>=17000)
	{
  	    for(TabID=4; TabID<=6; TabID++) 
	    {
		data = (TabID<<4) | (PSK8_TAB_SIZE-4);//11.0
		nim_reg_write(dev, R9D_RPT_DEMAP_BETA, &data, 1);
		nim_reg_write(dev, R11_DCC_OF_I, DatArray, 2);
		data = (TabID<<4) | (PSK8_TAB_SIZE-5);//10.5
		nim_reg_write(dev, R9D_RPT_DEMAP_BETA, &data, 1);
		nim_reg_write(dev, R11_DCC_OF_I, DatArray, 2);

		data = (TabID<<4) | (PSK8_TAB_SIZE-6);//10.0
		nim_reg_write(dev, R9D_RPT_DEMAP_BETA, &data, 1);
		nim_reg_write(dev, R11_DCC_OF_I, DatArray, 2);
		data = (TabID<<4) | (PSK8_TAB_SIZE-7);//9.5
		nim_reg_write(dev, R9D_RPT_DEMAP_BETA, &data, 1);
		nim_reg_write(dev, R11_DCC_OF_I, DatArray, 2);
	    }
	}
	//end of Rs<3M issue
	if(sym <= 1500)
	{	
		data = 0xf0 | 0;		//force old cr
		nim_reg_write(dev, R9D_RPT_DEMAP_BETA, &data, 1);
		TabVal = 0x19 | 0x8000;
		DatArray[0] = (UINT8)(TabVal & 0x0ff);
		DatArray[1] = (UINT8)((TabVal>>8) & 0x0ff);
		nim_reg_write(dev, R11_DCC_OF_I, DatArray, 2);

		data = 0xf0 | 3;	//enable snr est	
		nim_reg_write(dev, R9D_RPT_DEMAP_BETA, &data, 1);
		TabVal = 0x7fa | 0x8000;
		DatArray[0] = (UINT8)(TabVal & 0x0ff);
		DatArray[1] = (UINT8)((TabVal>>8) & 0x0ff);
		nim_reg_write(dev, R11_DCC_OF_I, DatArray, 2);

//pilot_on_gain=0,head_ped_gain=0 is same as M3501B for 1M pilot on lock slow issue
              nim_reg_read(dev, 0x127, &data, 1);		  
		data = data & 0x83;
		nim_reg_write(dev, 0x127, &data, 1);		
	}

	#ifdef HW_ADPT_CR_MONITOR
		data = 0xe6; // enable hw adpt CR report, also enable always update to regfile, latter need review
	#else
		data = 0xe0; // CR Tab init off
	#endif
	nim_reg_write(dev, R0E_ADPT_CR_CTRL, &data, 1);
#endif // HW_ADPT_CR
	return SUCCESS;
}

/*****************************************************************************
* static INT32 nim_s3503_autoscan_initial (struct nim_device *dev)
*
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_autoscan_initial (struct nim_device *dev)
{
	UINT8 data;
	UINT8 work_mode;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

	// Set Cap speed
	data = 0x3c;	//[7:6]: speed, [5:0] packet num.
	nim_reg_write(dev, RBD_CAP_PRM+1, &data, 1);

	// cap from AGC1
	nim_reg_read(dev, R70_CAP_REG+1, &data, 1);
	data = data & 0x40;
	nim_reg_write(dev, R70_CAP_REG+1, &data, 1);

	// cap from REG
	data = 0x00;
	nim_reg_write(dev, RBD_CAP_PRM, &data, 1);

	return SUCCESS;
}

/*****************************************************************************
* static INT32 nim_s3503_tso_initial (struct nim_device *dev)
*
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_tso_initial (struct nim_device *dev, UINT8 insert_dummy, UINT8 tso_mode)
{
	UINT8 data;
	UINT8 work_mode;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	data = 0x12;
	nim_reg_write(dev, RF0_HW_TSO_CTRL, &data, 1);
	NIM_PRINTF("            nim m3501c close dummy for dvbs \n");
	switch(tso_mode)
	{
		case 0 : {
			data = 0x37;
            // For C3503 only
            if(priv->ul_status.m_s3501_sub_type == NIM_C3503_SUB_ID)
            {
            	data = data ^ 0x02;
            }
			nim_reg_write(dev, RD8_TS_OUT_SETTING, &data, 1);
			NIM_PRINTF("            tso_mode is SSI \n"); break;
		}
		case 1 : {
			data = 0x27;
            // For C3503 only
            if(priv->ul_status.m_s3501_sub_type == NIM_C3503_SUB_ID)
            {
            	data = data ^ 0x02;
            }
			nim_reg_write(dev, RD8_TS_OUT_SETTING, &data, 1);
			NIM_PRINTF("            tso_mode is SPI \n"); break;
		}
	 }
/*
// For C3503 only
    if(priv->ul_status.m_s3501_sub_type == NIM_C3503_SUB_ID)
    {
        // Default ERRJ should be 0
        // Change ERRJ to 1 with bellow setting.
        nim_reg_read (dev, RF1_DSP_CLK_CTRL+4, &data, 1);
        data = data | 0x01;
        nim_reg_write(dev, RF1_DSP_CLK_CTRL+4, &data, 1);
    }
*/	  
	return SUCCESS;
}

/*****************************************************************************
* static INT32 nim_s3503_tso_bypass (struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_tso_bypass (struct nim_device *dev)
{
	UINT8 data;

	// Bypass TSO
	data = 0x01;
	nim_reg_write(dev, RAF_TSOUT_PAD, &data, 1);
	//
	nim_reg_read(dev, RF0_HW_TSO_CTRL+5, &data, 1);
	data = data | 0x80;
	nim_reg_write(dev, RF0_HW_TSO_CTRL+5, &data, 1);

	// Set FEC bit rate.
	data = 0x10;
	nim_reg_write(dev, RAD_TSOUT_SYMB+1, &data, 1);
	data = 0x04;
	nim_reg_write(dev, RAD_TSOUT_SYMB, &data, 1);
	NIM_PRINTF("            nim bypass TSO \n");

	return SUCCESS;
}


/*****************************************************************************
* static INT32 nim_s3503_tso_dummy_off (struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_tso_dummy_off (struct nim_device *dev)
{
	UINT8 data;
	nim_reg_read(dev, RF0_HW_TSO_CTRL, &data, 1);
	data = data & 0xfd;
	nim_reg_write(dev, RF0_HW_TSO_CTRL, &data, 1);
	NIM_PRINTF("            nim m3503 close dummy for dvbs \n");
	return SUCCESS;
}

/*****************************************************************************
* static INT32 nim_s3503_tso_dummy_on (struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_tso_dummy_on (struct nim_device *dev)
{
	UINT8 data;
	nim_reg_read(dev, RF0_HW_TSO_CTRL, &data, 1);
	data = data | 0x02;
	nim_reg_write(dev, RF0_HW_TSO_CTRL, &data, 1);
	//clear full then send mode of TSO
	nim_reg_read(dev, RF0_HW_TSO_CTRL, &data, 1);
	data = data & 0xbf;
	nim_reg_write(dev, RF0_HW_TSO_CTRL, &data, 1);
	NIM_PRINTF("            nim m3503 insert dummy\n");
	return SUCCESS;
}


/*****************************************************************************
* static INT32 nim_s3503_tso_soft_cbr (struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_tso_soft_cbr_on (struct nim_device *dev, UINT32 bitrate)
{
	UINT8 data;

	if (bitrate>512)
		bitrate = 512;
	data = (bitrate&0x0f)<<4;
	nim_reg_write(dev, RF0_HW_TSO_CTRL + 3, &data, 1);
	data = ((bitrate>>4)&0x1f) | 0x80;
	nim_reg_write(dev, RF0_HW_TSO_CTRL + 4, &data, 1);

	return SUCCESS;
}

/*****************************************************************************
* static INT32 nim_s3503_tso_soft_cbr_off (struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_tso_soft_cbr_off (struct nim_device *dev)
{
	UINT8 data;

	nim_reg_read(dev, RF0_HW_TSO_CTRL + 4, &data, 1);
	data = data & 0x7f;
	nim_reg_write(dev, RF0_HW_TSO_CTRL + 4, &data, 1);

	return SUCCESS;
}

/*****************************************************************************
* static INT32 nim_s3503_tso_off (struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_tso_off (struct nim_device *dev)
{
	UINT8 data;
	// close fec ts output
	nim_reg_read(dev, RAF_TSOUT_PAD, &data, 1);
	data = data | 0x10;
	nim_reg_write(dev, RAF_TSOUT_PAD, &data, 1);
	//NIM_PRINTF("            fec ts off\n");
	return SUCCESS;
}

/*****************************************************************************
* static INT32 nim_s3503_tso_on (struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_tso_on (struct nim_device *dev)
{
	UINT8 data;
	// Open fec ts output
	nim_reg_read(dev, RAF_TSOUT_PAD, &data, 1);
	data = data & 0xef;
	nim_reg_write(dev, RAF_TSOUT_PAD, &data, 1);
	NIM_PRINTF("            fec ts on\n");
	return SUCCESS;
}

/*****************************************************************************
* static INT32 nim_s3503_reg_get_modcod(struct nim_device *dev, UINT8 *modcod)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_reg_get_modcod(struct nim_device *dev, UINT8 *modcod)
{
	UINT8 data;
	//  NIM_PRINTF("Enter Fuction nim_s3503_reg_get_modcode \n");
	nim_reg_read(dev, RF8_MODCOD_RPT, &data, 1);
	*modcod = data & 0x7f;
	return SUCCESS;
	// bit0 : pilot on/off
	// bit[6:1] : modcod,
}

 /*****************************************************************************
* static INT32 nim_s3503_get_tune_freq(struct nim_device *dev, INT32 *freq)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_get_tune_freq(struct nim_device *dev, INT32 *freq)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

	*freq += priv->ul_status.m_StepFreq;
	if (*freq <= 0)
		*freq = 30;
	else if (*freq > 70)
		*freq = 70;

	//NIM_PRINTF("  tune *freq step is %d\n", *freq );
	return SUCCESS;
}

 /*****************************************************************************
* INT32 nim_s3503_reg_get_symbol_rate(struct nim_device *dev, UINT32 *sym_rate)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static  INT32 nim_s3503_reg_get_symbol_rate(struct nim_device *dev, UINT32 *sym_rate)
{
	UINT8 data[3];//, i;
	UINT32 sample_rate;
	UINT32 temp;
	UINT32 symrate;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	temp = 0;
        nim_reg_read(dev, R6C_RPT_SYM_RATE, data, 3);
//        symrate = (data[0]>>1) + (data[1] <<7)+((data[2]&0x01) <<15); // K S/s
        symrate = data[0] + (data[1] <<8)+((data[2]&0x01) <<16); 
        nim_s3503_get_dsp_clk(dev, &sample_rate);
        sample_rate = sample_rate/2;
        *sym_rate = nim_s3503_multu64div(symrate, sample_rate, 92160);
	return SUCCESS;
}

 /*****************************************************************************
* void nim_s3503_set_RS(struct nim_device *dev, UINT8 coderate)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static  void nim_s3503_set_RS(struct nim_device *dev, UINT32 rs)
{
	UINT8 data, ver_data[3];
        UINT32 sample_rate;
        UINT32 temp;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
    temp = 0;
	nim_s3503_get_dsp_clk(dev, &sample_rate);
	//NIM_PRINTF("\t\t dsp clock is %d\n", sample_rate);
        NIM_PRINTF("\t\t set ts %d with dsp clock %d\n", rs, sample_rate/1000);
        temp = nim_s3503_multu64div(rs, 184320, sample_rate); // 184320 == 90000 * 2.048
        if(temp>0x16800)
        {    
            NIM_PRINTF("\t\t NIM_Error: Symbol rate set error %d\n", temp);
            temp = 0x16800;
        }
        //CR3F
        ver_data[0] = (UINT8) (temp & 0xFF);
        ver_data[1] = (UINT8) ((temp & 0xFF00) >> 8);
        ver_data[2] = (UINT8) ((temp & 0x10000) >> 16);
        nim_reg_write(dev, R5F_ACQ_SYM_RATE, ver_data, 3);
	if (rs < 3000)
	{
		if (rs < 2000)
			data = 0x08;
		else
			data = 0x0a;
		nim_reg_write(dev, R1B_TR_TIMEOUT_BAND, &data, 1);
	}
	return ;
}

 /*****************************************************************************
* void nim_s3503_set_freq_offset(struct nim_device *dev, INT32 delfreq)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static  void nim_s3503_set_freq_offset(struct nim_device *dev, INT32 delfreq)
{
	//UINT8 data, ver_data, sample_rate;
        UINT8 data[3];
        UINT32 temp, delfreq_abs;
        UINT32 sample_rate;
	//UINT8   read_data;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
        //delfreq unit is KHz, sample_rate unit is KHz
        if(delfreq<0)
            delfreq_abs = 0 - delfreq;
        else
	    delfreq_abs = delfreq;
        nim_s3503_get_dsp_clk(dev, &sample_rate);
        temp = nim_s3503_multu64div(delfreq_abs, 92160, sample_rate); // 92160 == 90000 * 1.024
        if(temp>0xffff)
        {    
            NIM_PRINTF("\t\t NIM_Error: Symbol rate set error %d\n", temp);
            temp = 0xffff;
        }
        if(delfreq<0)
            temp = temp^0xffff | 0x10000;
        else
            temp = temp&0xffff ;
        //CR5C
        data[0] = (UINT8) (temp & 0xFF);
        data[1] = (UINT8) ((temp & 0xFF00) >> 8);
        data[2] = (UINT8) ((temp & 0x10000) >> 16);
        nim_reg_write(dev, R5C_ACQ_CARRIER, data, 3);
	return ;
}

//for SNR use
 /*****************************************************************************
* static UINT8 nim_s3503_get_SNR_index(struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static UINT8 nim_s3503_get_SNR_index(struct nim_device *dev)
{
	INT16 lpf_out16;
	INT16 agc2_ref5;
	INT32 snr_indx = 0;
	UINT8 data[2];
	UINT16 tdata[2];

	//CR45
	nim_reg_read(dev, R45_CR_LCK_DETECT, &data[0], 1);
	//CR46
	nim_reg_read(dev, R45_CR_LCK_DETECT + 0x01, &data[1], 1);

	tdata[0] = (UINT16) data[0];
	tdata[1] = (UINT16) (data[1] << 8);
	lpf_out16 = (INT16) (tdata[0] + tdata[1]);
	lpf_out16 /= (16 * 2);

	//CR07
	nim_reg_read(dev, R07_AGC1_CTRL, &data[0], 1);
	agc2_ref5 = (INT16) (data[0] & 0x1F);

	snr_indx = (lpf_out16 * agc2_ref5 / 21) - 27;//27~0

	if (snr_indx < 0)
		snr_indx = 0;
	else if (snr_indx > 176)
		snr_indx = 176;

	return snr_indx;
}

 /*****************************************************************************
* static INT32 nim_s3503_get_fft_result(struct nim_device *dev, UINT32 freq, UINT32 *start_adr)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_get_fft_result(struct nim_device *dev, UINT32 freq, UINT32 *start_adr)
{
	int i, index;
	int ave_energy, max_est, maxvalue;

	UINT8 data = 0x10;//,ver_data;
	UINT8 lock = 200;
	struct nim_s3501_private *dev_priv;

	dev_priv = (struct nim_s3501_private *)dev->priv;

	if (NULL == start_adr)
		return ERR_ADDRESS;
	//reset first
	nim_s3503_set_demod_ctrl(dev, NIM_DEMOD_CTRL_0X90);

	data = 0x35;////0x2B;
	nim_reg_write(dev, R0A_AGC1_LCK_CMD, &data, 1);

	dev_priv->nim_Tuner_Control(dev_priv->tuner_id, freq, 0);

	comm_sleep(10);
	dev_priv->nim_Tuner_Status(dev_priv->tuner_id, &lock);

	nim_s3503_cap_calculate_energy(dev);
	nim_s3501_smoothfilter();

	comm_memcpy((int *)start_adr, FFT_energy_1024, sizeof(FFT_energy_1024));
	//just deal with middle part of the data.
	//start from 256 to 767.
	//if needed, the range should be 0~1023, the whole array.

	start_adr[511] = (start_adr[510] + start_adr[512]) / 2;
	i = 0;ave_energy = 0;max_est = 0;
	for (index = 256; index <= 767; index++)
	{
		ave_energy += start_adr[index];
		if (i == (1 << (STATISTIC_LENGTH + 1)) - 1)
		{
			if (ave_energy > max_est)
				max_est = ave_energy;
			i = 0;
			ave_energy = 0;
		}
		else
		{
			i++;
		}
	}
	max_est = max_est / 8;
	maxvalue = max_est;

	for (index = 256; index <= 767; index++)
	{
		if ((start_adr[index] > (UINT32) maxvalue) && (start_adr[index] < (UINT32) (max_est * 2)))
			maxvalue = start_adr[index];
	}

	for (index = 256; index <= 767; index++)
	{
		if (start_adr[index] > (UINT32) maxvalue)
			start_adr[index] = maxvalue;
		//devider = maxvalue/250;
		start_adr[index] = start_adr[index] * 250 / maxvalue;
	}
	return SUCCESS;
}

 /*****************************************************************************
* INT32 nim_s3503_cap_fft_find_channel(struct nim_device *dev, UINT32 *tune_freq)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static  INT32 nim_s3503_cap_fft_find_channel(struct nim_device *dev, UINT32 *tune_freq)
{
	INT32 success;
	INT32 delta_fc_est[MAX_CH_NUMBER];
	INT32 SymbolRate_est[MAX_CH_NUMBER];
	INT32 IF_freq;
	INT32 ch_number;
	INT32 i;
	INT32 tune_jump_freq;
	INT32 tempFreq;
	INT32 temp, temp1;
	UINT8 data;
        UINT32 sample_rate, sample_tmp;

	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

	nim_s3503_cap_calculate_energy(dev);
	NIM_PRINTF("tune_freq = %d\n", *tune_freq);

       if(NIM_SCAN_SLOW == priv->blscan_mode)
       {
   		comm_memcpy( fft_energy_store,FFT_energy_1024,sizeof(FFT_energy_1024));
   		temp1 = fft_energy_store[511];
   		fft_energy_store[511] = (fft_energy_store[510]+fft_energy_store[512])/2;
   		for (i=6;i<1024-6;i++){
   			temp = 0;
   			for (data=0;data<12;data++)
   				temp = temp + fft_energy_store[i-6+data];
   			temp = temp/12;
   			FFT_energy_1024[i] = temp;
   		}
   		fft_energy_store[511] = temp1;
       }

	nim_s3501_autosearch((INT32 *) &success, (INT32 *) delta_fc_est, (INT32 *) SymbolRate_est, (INT32 *) &IF_freq, (INT32 *) &ch_number);

	nim_s3503_get_dsp_clk(dev, &sample_rate);

	if (1 == success)
	{
		for (i = 0; i < ch_number; i++)
		{
                        temp = nim_s3503_multu64div(delta_fc_est[i], sample_rate, 90000); //
			tempFreq = (*tune_freq)*1024 + temp;
			priv->ul_status.m_Freq[priv->ul_status.m_CRNum] = tempFreq;
			NIM_PRINTF("    m_Freq[%d] is %d\n", priv->ul_status.m_CRNum, priv->ul_status.m_Freq[priv->ul_status.m_CRNum]);
                        priv->ul_status.m_Rs[priv->ul_status.m_CRNum] = nim_s3503_multu64div(SymbolRate_est[i], sample_rate, 90000);
			priv->ul_status.m_CRNum++;
		}
	}
	else
	{
		//NIM_PRINTF("err\n");
		NIM_PRINTF("    Base band width is %d, ch_number is%d\n", IF_freq / 1024, ch_number);
	}
	IF_freq = nim_s3503_multu64div(IF_freq, sample_rate, 90000); //
	tune_jump_freq = IF_freq / 1024;
	return tune_jump_freq;
}

 /*****************************************************************************
* static INT32 nim_s3503_WidebandScan_open(struct nim_device *dev,UINT32 start_freq, UINT32 end_freq,UINT32 step_freq)
* Open
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
INT32 nim_s3503_WidebandScan_open(struct nim_device *dev,UINT32 start_freq, UINT32 end_freq,UINT32 step_freq)
{
    UINT32 full_size=0;

    NIM_PRINTF("Enter nim_s3503_WidebandScan_open\n");

    Last_Tuner_IF=0;
    chlspec_Num=0;
    called_num=0;

    full_size = (end_freq-start_freq)/step_freq;
    full_size = (full_size+2)*512;
    channel_spectrum=(INT32 *) comm_malloc(full_size * 4);
    if(channel_spectrum==NULL)
    {
        NIM_PRINTF("\n channel_spectrum--> no enough memory!\n");
        return ERR_NO_MEM;
    }

    if (nim_s3503_get_bypass_buffer(dev))
    {
        NIM_PRINTF("\n ADCdata--> no enough memory!\n");
        comm_free(channel_spectrum);
        return ERR_NO_MEM;
    }

    return SUCCESS;

}

 /*****************************************************************************
* static INT32 nim_s3503_autoscan_WidebandScan_close()
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
 INT32 nim_s3503_WidebandScan_close()
{
    comm_free(channel_spectrum);
    return SUCCESS;
}

 /*****************************************************************************
* static INT32 nim_s3503_autoscan_WidebandScan(struct nim_device *dev,UINT32 start_freq, UINT32 end_freq)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
INT32 nim_s3503_WidebandScan(struct nim_device *dev,UINT32 start_freq, UINT32 end_freq)
{
    UINT32 FFT_freq=0;
    UINT32 i=0,j=0;
    UINT32 ADC_sample_freq=0;
    UINT32  step_freq=0;
    struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

    NIM_PRINTF("Enter nim_s3503_WidebandScan\n");

    ADC_sample_freq=96;
    step_freq=ADC_sample_freq/2;  

    if(SUCCESS == nim_s3503_WidebandScan_open(dev,start_freq,end_freq,step_freq))
    {
        for (FFT_freq = start_freq; FFT_freq < end_freq; FFT_freq += step_freq)
        {
            nim_s3503_set_demod_ctrl(dev, NIM_DEMOD_CTRL_0X91);
            comm_memset(FFT_energy_1024, 0, sizeof(FFT_energy_1024));
            for(j=0;j<100;j++)
            {
                nim_s3503_cap_start(dev, FFT_freq, 0, FFT_energy_1024);
                for(i=0;i<1024;i++)
                {
                    if(FFT_energy_1024[i]>0)
                        break;
                }
                if(i<1024)
                    break;
            }

            if(100 == j)
            {
                comm_free(priv->ul_status.ADCdata_malloc_addr);
                NIM_PRINTF("nim_s3503_WidebandScan works wrong !\n");
                NIM_PRINTF("ERR_FAILURE, Leave nim_s3503_WidebandScan!\n");
                return ERR_FAILURE;
            }
            nim_s3501_FFT_WidebandScan(dev,FFT_freq,ADC_sample_freq);
        }
        comm_free(priv->ul_status.ADCdata_malloc_addr);
        NIM_PRINTF("SUCCESS, Leave nim_s3503_WidebandScan!\n");
        return SUCCESS;
    }
    else
    {
        NIM_PRINTF("ERR_NO_MEM, Leave nim_s3503_WidebandScan!\n");
        return ERR_NO_MEM;
    }
}
 /*****************************************************************************
* void nim_s3503_cap_fft_result_read(struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static  void nim_s3503_cap_fft_result_read(struct nim_device *dev)
{
	UINT8 data = 0;
	UINT8 read_data = 0;
	INT32 m = 0;

	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

	nim_s3503_set_demod_ctrl(dev, NIM_DEMOD_CTRL_0X91);

	nim_s3503_set_dsp_clk (dev, 96);

	nim_s3503_set_adc(dev);

	nim_s3503_interrupt_mask_clean(dev);

	// tso dummy off
	nim_s3503_tso_dummy_off(dev);
	//CR07
	nim_s3503_set_agc1(dev, 0x00, NIM_OPTR_FFT_RESULT);

	//CRBE
	data = 0x01;
	nim_reg_write(dev, RBD_CAP_PRM + 1, &data, 1);

	data = 0x55; ////0x2B; let AGC can not lock, try to modify tuner's gain
	nim_reg_write(dev, R0A_AGC1_LCK_CMD, &data, 1);

	nim_s3503_set_demod_ctrl(dev, NIM_DEMOD_CTRL_0X52);

	comm_delay(1000);
	memset(priv->ul_status.ADCdata_malloc_addr,0,0x20000 * 2);

	dmx_pause((struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, 0));
	nim_s3501_autoscan_signal_input(dev,NIM_SIGNAL_INPUT_OPEN);

	data = 0x50; ////0x2B; let AGC  lock, try to modify tuner's gain
	nim_reg_write(dev, R0A_AGC1_LCK_CMD, &data, 1);

	for (m = 0; m < 1000; m++)
	{
		comm_delay(1000);
		nim_reg_read(dev, R02_IERR, &read_data, 1);
		if (0x01 == (read_data & 0x01))
		{
			nim_s3503_cap_IQ_enerage(dev);

			//do software 1024 points R2 FFT
			R2FFT(priv->ul_status.FFT_I_1024, priv->ul_status.FFT_Q_1024);
			NIM_PRINTF(" ADC DATA  transfer finish\n");
			break;
		}
	}
	nim_s3501_autoscan_signal_input(dev,NIM_SIGNAL_INPUT_CLOSE);
	dmx_start((struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, 0));
	//NIM_PRINTF("  leave Fuction nim_s3503_cap_fft_result_read \n");
}

#ifdef NIM_CAPTURE_SUPPORT
 /*****************************************************************************
* INT32 nim_s3503_cap_start(struct nim_device *dev, UINT32 startFreq, UINT32 sym, UINT32 *cap_buffer)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_cap_start(struct nim_device *dev, UINT32 startFreq, UINT32 sym, UINT32 *cap_buffer)
{
	INT32 i;
	UINT8   data = 0x10;
	UINT8   low_sym = 0;
	INT32   result = 200;
	UINT8   lock = 200;
	UINT8 ver_data;
	struct nim_s3501_private *dev_priv;
	dev_priv = (struct nim_s3501_private *)dev->priv;

	NIM_PRINTF("Enter nim_s3503_cap_start : Tuner_IF=%d\n",startFreq);

	nim_s3503_set_agc1(dev,low_sym,NIM_OPTR_CHL_CHANGE);

	result = dev_priv->nim_Tuner_Control(dev_priv->tuner_id,startFreq, sym);
	if (result==SUCCESS)
		NIM_PRINTF("nim_Tuner_Control OK\n");
	else
       {
		NIM_PRINTF("nim_Tuner_Control failed\n");
        }

	lock=0;
	for( i=0; i<1000; i++ )
	{
		comm_delay(1000);
		result = dev_priv->nim_Tuner_Status(dev_priv->tuner_id,&lock);
		if (lock)
		{
			NIM_PRINTF("Tuner lock after %d times delay\n",i+1);
			break;
		}
	}
	if(lock==0)
      {
		NIM_PRINTF("Tuner can not lock\n");
       }
	
	nim_s3503_set_adc(dev);
	nim_s3503_set_agc1(dev,low_sym,NIM_OPTR_CHL_CHANGE);
    nim_s3503_cap_calculate_energy(dev);

	return SUCCESS;
}

 /*****************************************************************************
* INT32 nim_s3503_cap(struct nim_device *dev, UINT32 startFreq, UINT32 *cap_buffer, UINT32 sym)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static  INT32 nim_s3503_cap(struct nim_device *dev, UINT32 startFreq, UINT32 *cap_buffer, UINT32 sym)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

	NIM_PRINTF("Enter nim_s3503_cap : Tuner_IF=%d\n",startFreq);
	if (nim_s3503_get_bypass_buffer(dev))
		return ERR_NO_MEM;
	nim_s3503_cap_start(dev, startFreq, sym, cap_buffer);
	comm_free((int *)priv->ul_status.ADCdata_malloc_addr);
	return SUCCESS;
}

#endif





 /*****************************************************************************
* static INT32 nim_S3501_adc2mem_entity(struct nim_device *dev, UINT32 startFreq, UINT32 *cap_buffer, UINT32 sym)
* capture RX_ADC data to DRAM
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT32 startFreq
*  Parameter3: UINT32 *cap_buffer
*       The base addr for DRAM buffer
*  Parameter4: UINT32 sym
*  Parameter5: UINT32 dram_len
*
* Return Value: INT32
*****************************************************************************/
static  INT32 nim_s3503_adc2mem_entity(struct nim_device *dev,  UINT8 *cap_buffer, UINT32 dram_len)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	UINT8 data;
	UINT8 is_test_mode=0,user_force_stop_adc_dma=0;
       UINT32 dram_base;
	   
       dram_base = (UINT32)cap_buffer;
	//Reset ADCDMA.	  
   	nim_reg_read(dev,0x100, &data, 1);
	data |= 0x40;	
	nim_reg_write(dev,0x100, &data, 1);
	//check reset is done
	nim_reg_read(dev,0x100, &data, 1);
	while(1){
		if(data&0x01){
			NIM_PRINTF("Reset ADCDMA done\n");
			break;
			}
		nim_reg_read(dev,0x100, &data, 1);
	}

	//Configure DRAM base address, unit is 32bytes
	dram_base &=  0x7fffffe0;
	NIM_PRINTF("Enter function %s with DRAM base address: 0x%08x\n",__FUNCTION__,dram_base);	
	dram_base = (dram_base&0xffffffff)>>5;
	data = (UINT8)(dram_base&0xff);
	nim_reg_write(dev,0x104, &data, 1);
	data = (UINT8)((dram_base>>8)&0xff);
	nim_reg_write(dev,0x105, &data, 1);
	data = (UINT8)((dram_base>>16)&0xff);
	nim_reg_write(dev,0x106, &data, 1);
	data = (UINT8)((dram_base>>24)&0xff);
	nim_reg_write(dev,0x107, &data, 1);

 	//Configure DRAM length, can support 1G byte, but should consider with base address 
 	//and make sure that it is not beyond availbe sdram range.
	if (dram_len > 0x10000000)
	    dram_len = 0x10000000;
	dram_len = (dram_len>>15);	// unit is 32K byte

	NIM_PRINTF("\t Configure DRAM length: 0x%08x.\n", dram_len<<15);
	data = (UINT8)(dram_len&0xff);
	nim_reg_write(dev,0x108, &data, 1);
	data = (UINT8)((dram_len>>8)&0xff);
	nim_reg_write(dev,0x109, &data, 1);

	//Configure capture points, reg102[3:0]
	//0:ADC_OUT 1:DCC_OUT 2:IQB_OUT 3:DC_OUT
	//4:FLT_OUT 5:AGC2_OUT 6:TR_OUT 7:EQ_OUT
	//8:PLDS_OUT 9:AGC3_OUT 10:DELAY_PLL_OUT 11:CR_OUT 	
	nim_reg_read(dev,0x102, &data, 1);
	data |= 0x00;
	nim_reg_write(dev,0x102, &data, 1);
	// select sram shared
	nim_reg_read(dev,0x111, &data, 1);
	data |= 0x20;
	nim_reg_write(dev,0x111, &data, 1);

	//Configure test pattern mode if in test mode.
	if (is_test_mode)
	{
		NIM_PRINTF("\t Configure test pattern mode and test mode.\n");
		nim_reg_read(dev,0x101, &data, 1);	// enable test mode
		data |= 0x01;
		nim_reg_write(dev,0x101, &data, 1);

		if (2==is_test_mode)
		{
			nim_reg_read(dev,0x100, &data, 1);	// test mode 1: pn seq, 0: counter by 1 
			data |= 0x80;
			nim_reg_write(dev,0x100, &data, 1);
		}
	}

	//Reset ADCDMA.	  
   	nim_reg_read(dev,0x100, &data, 1);
	data |= 0x40;	
	nim_reg_write(dev,0x100, &data, 1);

	//Start ADC DMA
	NIM_PRINTF("\t Start ADC DMA.\n");


	nim_reg_read(dev,0x100, &data, 1);
	data |= 0x20;
	nim_reg_write(dev,0x100, &data, 1);

	//Wait ADC DMA finish.
	NIM_PRINTF("\t Wait ADC DMA finish.\n");
	while(1)
	{
		if (user_force_stop_adc_dma)
		{
			user_force_stop_adc_dma = 0;
			nim_reg_read(dev,0x100, &data, 1);
			data |= 0x40;
			nim_reg_write(dev,0x100, &data, 1);
			NIM_PRINTF("ADC_DMA force stopped by user.\n");
			break;
		}
		nim_reg_read(dev,0x100, &data, 1);
		NIM_PRINTF("\t Waiting: ... CR 0x100: 0x%02x.\n", data);

		if (data&0x10)
		{
			NIM_PRINTF("ADC_DMA overflowed.\n");
			break;
		}

		if (data&0x08)
		{
			NIM_PRINTF("ADC_DMA finished.\n");
			break;
		}
		comm_sleep(50);
	}

	NIM_PRINTF("%s Exit.\n",__FUNCTION__);
	
	//Reset ADCDMA.	  
   	nim_reg_read(dev,0x111, &data, 1);
	data &= 0xdf;	
	nim_reg_write(dev,0x111, &data, 1);
	
   	nim_reg_read(dev,0x100, &data, 1);
	data |= 0x40;	
	nim_reg_write(dev,0x100, &data, 1);
	
	return SUCCESS;
}

 /*****************************************************************************
* void nim_s3503_adc2mem_calculate_energy(struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static  INT32 nim_s3503_adc2mem_calculate_energy(struct nim_device *dev,UINT8 *cap_buffer,UINT32 dram_len)
{
	INT32 i, j, k, m,n;//,printf_1 = 1;
	INT32 energy_real, energy_imag;//unsigned energy
	INT32 energy;//unsigned energy
	INT32 energy_tmp;
	INT32 fft_I, fft_Q;
	UINT8 data;
	UINT8 *data_ptr;
	//UINT8    data_1[2];
	UINT32 OldIDPos, Find11Packet, PacketNum;
	UINT32 NO_S3501ID;
	UINT32 overflow_cnt = 0;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	comm_memset(FFT_energy_1024, 0, sizeof(FFT_energy_1024));

	// capture 64Kbyte ADC2DRAM data 
      nim_s3503_adc2mem_entity( dev,  cap_buffer, dram_len);
    //libc_printf("adc2dram begin\n");

         for(k=0;k<20;k++)
         { 
         	data_ptr = cap_buffer+k*2048;
    		 //uppack the I/Q data     	
		//MEMCPY(priv->ul_status.ADCdata, cap_buffer+k*2048 , 2048);
		for (i = 0; i < 1024; i++)
		{
			//fft_I = priv->ul_status.ADCdata[2 * i];
			//fft_Q = priv->ul_status.ADCdata[2 * i + 1];
			fft_I = data_ptr[2 * i];
			fft_Q = data_ptr[2 * i + 1];
         /*   if(k<7)
            {
            libc_printf("sample_%04d is %02x%02x\n", i+k*1024, fft_I, fft_Q);
            comm_sleep(10);
            } 
            */
			if (fft_I & 0x80)
				fft_I |= 0xffffff00;
			if (fft_Q & 0x80)
				fft_Q |= 0xffffff00;

			m = 0;for (j = 0; j < 10; j++)
			{
				  	m <<= 1;m += ((i >> j) & 0x1);
			}//address change for 1024 FFT
			fft_I = fft_I << (FFT_BITWIDTH - 8);
			fft_Q = fft_Q << (FFT_BITWIDTH - 8);         	
			priv->ul_status.FFT_I_1024[m] = fft_I;
			priv->ul_status.FFT_Q_1024[m] = fft_Q;
		}
	         // calculate FFT
		R2FFT(priv->ul_status.FFT_I_1024, priv->ul_status.FFT_Q_1024);
 
		//accumulation
		for (i = 0; i < 1024; i++)
		{
			fft_I = priv->ul_status.FFT_I_1024[i];
			fft_Q = priv->ul_status.FFT_Q_1024[i];

			energy_real = fft_I * fft_I;
			energy_imag = fft_Q * fft_Q;
			energy = energy_real + energy_imag;
			//because 20 times of accumulation needed, result will extend 5 bits
			//nevertherless maximum energy of possible signal(eg. 2Msps) is 5 times 				//lessthan theoretic max energy, ie. 2 bits less
			//if x is maximum FFT level, x^2/20 is maximum signal(2Msps) energy level(psd)
			//if we clip the MSB in FFT module(when FFT layer is 5), the maximum energy is  		//x^2/4
			//so we can get above conclusion
			//so we only need to reduce 3 bits LSB of accumulation result
			energy >>= 3;
			j = (i + 511) & 1023;//fold FFT sequence to natural sequence
			//energy_tmp = FFT_energy_1024_tmp[j] + energy;
			//energy_tmp=FFT_energy_1024[j]+energy*20;
			energy_tmp =  energy;
			//  		FFT_energy_1024[j] = fft_I;

			if ((energy_tmp >> 20) & 1)
			{
				FFT_energy_1024_tmp[j] = 1048575;//maximum unsigned value of 20 bits
			}
			else
			{
				FFT_energy_1024_tmp[j] = energy_tmp;
			}
		}
		for(n=0;n<1024;n++)
		{
			FFT_energy_1024[n] += FFT_energy_1024_tmp[n];
		}
         	}
		 
       //  libc_printf("adc2dram end\n");
       return SUCCESS;
 }

/*****************************************************************************
* INT32 nim_s3503_adc2mem_start(struct nim_device *dev, UINT32 startFreq, UINT32 sym, UINT32 *cap_buffer)
*    capture dram_len bytes RX_ADC data to DRAM, and calculate FFT result for spectrum for autoscan.
*
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT32 startFreq
*  Parameter3: UINT32 *cap_buffer
*       Not used, because the DRAM buffer is allocated and free in this function 
*  Parameter4: UINT32 sym
*       always '0', set tuner_lpf_bandwidth = tuner's top bandwidth for autoscan
*  Parameter5: UINT32 dram_len
*
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_adc2mem_start(struct nim_device *dev, UINT32 startFreq, UINT32 sym, UINT32 *cap_buffer, UINT32 dram_len)
{
	INT32 i;
	UINT32  freq = 0;
	UINT8   data = 0x10;
	UINT8   low_sym = 0;
	INT32   result = 200;
	UINT8   lock = 200;
	UINT8 ver_data;
	struct nim_s3501_private *dev_priv;
	UINT8  *dram_base_t;
	dev_priv = (struct nim_s3501_private *)dev->priv;
	
    dram_base_t=(UINT8 *) MALLOC(dram_len );
	if(NULL==dram_base_t)
	{
	    NIM_PRINTF("S3503 adc2mem memory allocation error!\n");	
	    return ERR_FAILUE;
	}
	result = dev_priv->nim_Tuner_Control(dev_priv->tuner_id,startFreq, sym);
	if (result==SUCCESS)
		NIM_PRINTF("nim_Tuner_Control OK\n");
	else
       {
		NIM_PRINTF("nim_Tuner_Control failed\n");
        }

	lock=0;
	for( i=0; i<1000; i++ )
	{
		comm_delay(1000);
		result = dev_priv->nim_Tuner_Status(dev_priv->tuner_id,&lock);
		if (lock)
		{
			NIM_PRINTF("Tuner lock after %d times delay\n",i+1);
			break;
		}
	}
	if(lock==0)
       {
		NIM_PRINTF("Tuner can not lock\n");
       }
    
    comm_delay(10000);  //wait 5ms for agc1 stable     
    nim_s3503_adc2mem_calculate_energy(dev,dram_base_t,dram_len);
    
	comm_free(dram_base_t);
	
	return SUCCESS;
}

  /*****************************************************************************
 * INT32 nim_S3501_adc2mem_cap(struct nim_device *dev, UINT32 startFreq, UINT32 sym, UINT32 *cap_buffer, UINT32 dram_len)
 * capture dram_len bytes RX_ADC data to DRAM, and calculate FFT result for spectrum. 
 *
 * Arguments:
 *  Parameter1: struct nim_device *dev
 *  Parameter2: UINT32 startFreq
 *  Parameter3: UINT32 *cap_buffer
 *       The base addr for DRAM buffer
 *  Parameter4: UINT32 sym
 *       if(sym == 0)    tuner_lpf_bandwidth = tuner's top bandwidth
 *       else            tuner_lpf_bandwidth = sym
 *  Parameter5: UINT32 dram_len
 *
 * Usage:
 *      cap_buffer=(UINT8 *) MALLOC(dram_len );
 *      nim_S3501_adc2mem_cap(dev,startFreq,sym,cap_buffer,dram_len);
 * Return Value: INT32
 *****************************************************************************/
 static  INT32 nim_s3503_adc2mem_cap(struct nim_device *dev, UINT32 startFreq, UINT32 sym, UINT32 *cap_buffer, UINT32 dram_len)
 {
 	INT32 i;
	UINT32  freq = 0;
	UINT8   data = 0x10;
	UINT8   low_sym = 0;
	INT32   result = 200;
	UINT8   lock = 200;
	UINT8 ver_data;
	struct nim_s3501_private *dev_priv;
	UINT8  *dram_base_t;
	dev_priv = (struct nim_s3501_private *)dev->priv;
	
       //dram_base_t=(UINT8 *) MALLOC(dram_len );
    dram_base_t = (UINT8  *)cap_buffer;
	if(NULL==dram_base_t)
	{
	    NIM_PRINTF("S3503 adc2mem memory allocation error!\n");	
	    return ERR_FAILUE;
	}
	result = dev_priv->nim_Tuner_Control(dev_priv->tuner_id,startFreq, sym);
	if (result==SUCCESS)
		NIM_PRINTF("nim_Tuner_Control OK\n");
	else
       {
		NIM_PRINTF("nim_Tuner_Control failed\n");
       }

	lock=0;
	for( i=0; i<1000; i++ )
	{
		comm_delay(1000);
		result = dev_priv->nim_Tuner_Status(dev_priv->tuner_id,&lock);
		if (lock)
		{
			NIM_PRINTF("Tuner lock after %d times delay\n",i+1);
			break;
		}
	}
	if(lock==0)
       {
		NIM_PRINTF("Tuner can not lock\n");
       }
	
	nim_s3503_set_adc(dev);
	nim_s3503_set_demod_ctrl(dev, NIM_DEMOD_CTRL_0X91);
	nim_s3503_set_dsp_clk (dev, 96);
	nim_s3503_interrupt_mask_clean(dev);
    
	// Config AGC1 register CR07 to adjuct AGC1 target
	//nim_s3503_set_agc1(dev, 0x00, NIM_OPTR_FFT_RESULT);  // AGC1 target is autoscan mode
	nim_s3503_set_agc1(dev,low_sym,NIM_OPTR_CHL_CHANGE);   // AGC1 target is channel_change mode	
    
    // a difference btw adc2dram and capture, in adc2dram agc1 must be set to unlock to make sure FSM at AGC1 state
	data = 0x55; ////0x2B; let AGC can not lock, try to modify tuner's gain
	nim_reg_write(dev, R0A_AGC1_LCK_CMD, &data, 1);	
	nim_s3503_set_demod_ctrl(dev, NIM_DEMOD_CTRL_0X52);  
    
    comm_delay(10000);  //wait 5ms for agc1 stable
    nim_s3503_adc2mem_calculate_energy(dev,dram_base_t,dram_len);
    
	data = 0x50; ////0x2B; let AGC  lock, try to modify tuner's gain
	nim_reg_write(dev, R0A_AGC1_LCK_CMD, &data, 1);	   
	
	//comm_free(dram_base_t);	
	return SUCCESS;
 
 }

 
 /*****************************************************************************
* static INT32 nim_s3503_get_bypass_buffer(struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_get_bypass_buffer(struct nim_device *dev)
{
	// According to DMX IC spec, bypass buffer must locate in 8MB memory segment.
	// Bypass buffer size is (BYPASS_BUFFER_REG_SIZE * 188)
	#define BYPASS_BUF_SIZE 0x20000 	// 128 KB
	#define BYPASS_BUF_MASK (BYPASS_BUF_SIZE - 1)
	UINT32 tmp;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

	priv->ul_status.ADCdata_malloc_addr=(UINT8 *) comm_malloc(BYPASS_BUF_SIZE * 2);
	if (priv->ul_status.ADCdata_malloc_addr == NULL)
		return ERR_NO_MEM;

	NIM_PRINTF("ADCdata_malloc_addr=0x%08x\n", priv->ul_status.ADCdata_malloc_addr);

	comm_memset((int *)priv->ul_status.ADCdata_malloc_addr, 0, BYPASS_BUF_SIZE * 2);
	tmp = ((UINT32) (priv->ul_status.ADCdata_malloc_addr)) & BYPASS_BUF_MASK;
	if (tmp)
		priv->ul_status.ADCdata = priv->ul_status.ADCdata_malloc_addr + BYPASS_BUF_SIZE - tmp;
	else
		priv->ul_status.ADCdata = priv->ul_status.ADCdata_malloc_addr;
	
	NIM_PRINTF("ADCdata=0x%08x\n", priv->ul_status.ADCdata);

	return SUCCESS;
}


/*****************************************************************************
* static INT32 nim_s3503_autoscan(struct nim_device *dev, struct NIM_Auto_Scan *pstAuto_Scan)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_autoscan(struct nim_device *dev, struct NIM_Auto_Scan *pstAuto_Scan)
{
    UINT8 cur_fec=0; 
    UINT32 cur_freq=0, cur_sym=0;
    INT32 i=0,j=0, ret = SUCCESS;
    INT32 crnum;
    UINT32 FFT_freq, step_freq = 0;
    UINT32 FFT_result;
    UINT8 data;  
    UINT8 chcnt,double_i=0;
    UINT32 temp,temp_step=0;
    UINT32 sym,freq,last_lock_rs;
    INT32 success;
    INT32 last_lock_freq=0, temp_freq=0;
    struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
    INT32 ADC_sample_freq=0;
    UINT32 start_t,end_t,temp_t;
    INT32 Bug_Freq[2];
    INT32 Bug_Sym[2];
    INT32 Scan_mode=0;
    INT32 loop=1;
    INT32 loop_index=0;
    
    NIM_PRINTF("\t Start autoscan \n");
    AUTOSCAN_PRINTF("Enter nim_s3503_autoscan : sfreq = %d, efreq = %d\n",pstAuto_Scan->sfreq, pstAuto_Scan->efreq);
    start_t=OS_GetTickCount();
    AutoScan_or_ChannelChange=0;
#ifdef AUTOSCAN_DEBUG
    config_data = priv->Tuner_Config_Data.QPSK_Config;
    priv->Tuner_Config_Data.QPSK_Config |= M3501_SIGNAL_DISPLAY_LIN;
#endif
#ifdef CHANNEL_CHANGE_ASYNC
    UINT32 flag_ptn = 0;
    if(NIM_FLAG_WAIT(&flag_ptn, priv->flag_id, NIM_FLAG_CHN_CHG_START|NIM_FLAG_CHN_CHANGING,OSAL_TWF_ORW, 0) == OSAL_E_OK)
    {
        priv->ul_status.s3501_chanscan_stop_flag = 1;
        comm_sleep(10);
    }
#endif
    priv->tsk_status.m_lock_flag = NIM_LOCK_STUS_NORMAL;
    if (pstAuto_Scan->sfreq <AS_FREQ_MIN || pstAuto_Scan->efreq> AS_FREQ_MAX || pstAuto_Scan->sfreq > pstAuto_Scan->efreq)
    {
        return ERR_FAILUE;
    }
    // reset HW FSM
    nim_s3503_set_demod_ctrl(dev, NIM_DEMOD_CTRL_0X90);
    nim_s3503_ioctl(dev, NIM_DRIVER_STOP_ATUOSCAN, 0);
    data = 0x1f; // setting for soft search function
    nim_reg_write(dev, R1B_TR_TIMEOUT_BAND, &data, 1);
    nim_s3503_cr_setting(dev, NIM_OPTR_SOFT_SEARCH);
    nim_s3503_TR_CR_Setting(dev, NIM_OPTR_SOFT_SEARCH);
    nim_s3503_fec_set_ldpc(dev, NIM_OPTR_SOFT_SEARCH, 0x00, 0x01);
    nim_s3503_set_hbcd_timeout(dev, NIM_OPTR_SOFT_SEARCH);
    nim_s3503_autoscan_initial( dev);
    nim_s3503_tso_on(dev);
#ifdef ADC2DRAM_SUPPORT   
    nim_s3503_set_adc(dev);
    nim_s3503_set_demod_ctrl(dev, NIM_DEMOD_CTRL_0X91);
    nim_s3503_set_dsp_clk (dev, 96);
    nim_s3503_set_adc(dev);
    nim_s3503_interrupt_mask_clean(dev);
    nim_s3503_set_agc1(dev, 0x00, NIM_OPTR_FFT_RESULT);	
    // a difference btw adc2dram and capture, in adc2dram agc1 must be set to unlock to make sure FSM at AGC1 state
    data = 0x55; ////0x2B; let AGC can not lock, try to modify tuner's gain
    nim_reg_write(dev, R0A_AGC1_LCK_CMD, &data, 1);	
    nim_s3503_set_demod_ctrl(dev, NIM_DEMOD_CTRL_0X52);
#endif	
    Last_Tuner_IF=0;
    chlspec_Num=0;
    called_num=0;	
    Max_FFT_energy=0;
	
    channel_spectrum=(INT32 *) comm_malloc(FS_MAXNUM * 4);
    if(channel_spectrum==NULL)
    {
        AUTOSCAN_PRINTF("\n channel_spectrum--> no enough memory!\n");
        return ERR_NO_MEM;
    }

    channel_spectrum_tmp=(INT32 *) comm_malloc(FS_MAXNUM * 4);
    if(channel_spectrum_tmp==NULL)
    {
        AUTOSCAN_PRINTF("\n channel_spectrum_tmp--> no enough memory!\n");
        comm_free(channel_spectrum);
        return ERR_NO_MEM;
    }
	
    if (nim_s3503_get_bypass_buffer(dev))
    {
        AUTOSCAN_PRINTF("\n ADCdata--> no enough memory!\n");
        comm_free(channel_spectrum);
        comm_free(channel_spectrum_tmp);
        return ERR_NO_MEM;
    }
    ADC_sample_freq=96;
    step_freq=ADC_sample_freq/2;
    for (FFT_freq = pstAuto_Scan->sfreq; FFT_freq < pstAuto_Scan->efreq; FFT_freq += step_freq)
    {
        comm_memset(FFT_energy_1024, 0, sizeof(FFT_energy_1024));
        while(1)
        {			
#ifdef ADC2DRAM_SUPPORT
            nim_s3503_adc2mem_start(dev, FFT_freq, 0, FFT_energy_1024,BYPASS_BUF_SIZE_DMA);
#else
            nim_s3503_set_demod_ctrl(dev, NIM_DEMOD_CTRL_0X91);        
            nim_s3503_cap_start(dev, FFT_freq, 0, FFT_energy_1024);
#endif
            for(i=0;i<1024;i++)
            {
                if(FFT_energy_1024[i]>0)
                    break;
            }
            if(i<1024)    break;

            if(priv->ul_status.s3501_autoscan_stop_flag)
            {
                comm_free(channel_spectrum);
                comm_free(channel_spectrum_tmp);
                comm_free((int *)priv->ul_status.ADCdata_malloc_addr);
                AUTOSCAN_PRINTF("\tleave fuction nim_s3503_autoscan\n");
                return SUCCESS;
            }
        }
        called_num++;
        if(1==((S3503_Debug_Flag>>1)&0x01))
        {
            AUTOSCAN_PRINTF("call_num=%d,Tuner_IF=%d \n",called_num,FFT_freq);
            AUTOSCAN_PRINTF("FFT1024-> 0000 : 1000000 \n");
            for(i=0;i<1024;i++)
                AUTOSCAN_PRINTF("FFT1024-> %4d : %d \n",i,FFT_energy_1024[i]);
        }
        
        if(NIM_SCAN_SLOW == priv->blscan_mode)
        {
            Scan_mode=1;
        }
        else
        {
            Scan_mode=0;
        }
        nim_s3501_MedianFilter(1024,FFT_energy_1024,Scan_mode); // Median filter for restrain single tone noise
        nim_s3501_FFT_WidebandScan(dev,FFT_freq,ADC_sample_freq);
        if(priv->ul_status.s3501_autoscan_stop_flag)
        {
            comm_free(channel_spectrum);
            comm_free(channel_spectrum_tmp);
            comm_free((int *)priv->ul_status.ADCdata_malloc_addr);
            AUTOSCAN_PRINTF("\tleave fuction nim_s3503_autoscan\n");
            return SUCCESS;
        }
    }
#ifdef ADC2DRAM_SUPPORT    
    data = 0x50; ////0x2B; let AGC  lock, try to modify tuner's gain
    nim_reg_write(dev, R0A_AGC1_LCK_CMD, &data, 1);	
#endif
    comm_free((int *)priv->ul_status.ADCdata_malloc_addr);
    end_t=OS_GetTickCount();
    temp_t=end_t;
    AUTOSCAN_PRINTF("\tWideband FFT cost time %dms\n",end_t-start_t);
    if(1==((S3503_Debug_Flag>>2)&0x01))
    {
        for(i=0;i<chlspec_Num;i++)
        AUTOSCAN_PRINTF("FFT_WBS-->%d : %d\n",i,channel_spectrum[i]);
    }
    end_t=OS_GetTickCount();
    AUTOSCAN_PRINTF("\tPrint FFT result cost time %dms\n",end_t-temp_t);
    temp_t=end_t;

    AUTOSCAN_PRINTF("Max_FFT_energy=%d\n",Max_FFT_energy);
    loop=1;
    if(Max_FFT_energy>8388607)
    {
        loop=2;
    }
    AUTOSCAN_PRINTF("************loop=%d****************\n",loop);
    if(loop==2)
    {
        for(i=0;i<chlspec_Num;i++)
        {
            channel_spectrum_tmp[i]=channel_spectrum[i]/(8388607>>5);
	     if(channel_spectrum_tmp[i]<=0)
	         channel_spectrum_tmp[i]=1;
	     else if(channel_spectrum_tmp[i]>8388607)
		  channel_spectrum_tmp[i]=8388607;

	     if (channel_spectrum[i]>8388607)    // max 23bit = 0x7fffff
		  channel_spectrum[i]=8388607;
	     else if(channel_spectrum[i]==0) 
		  channel_spectrum[i]=1;
        }
    }
    
    ////******find TP***
    TP_number=0;
    comm_memset(Frequency_Est, 0, sizeof(Frequency_Est));
    comm_memset(SymbolRate_Est, 0, sizeof(SymbolRate_Est));
    //nim_s3501_SearchTP(&success, Frequency_Est, SymbolRate_Est, &TP_number, chlspec_Num, channel_spectrum,pstAuto_Scan->sfreq,ADC_sample_freq);
    for(loop_index=0;loop_index<loop;loop_index++)
    {
        if(loop_index==0)
        {
            nim_s3501_SearchTP(chlspec_Num, channel_spectrum, pstAuto_Scan->sfreq, ADC_sample_freq,loop_index);
            AUTOSCAN_PRINTF("Time %d : Find TP number is %d\n",loop_index,TP_number);
        }
        else if(loop_index==1)
        {
            nim_s3501_SearchTP(chlspec_Num, channel_spectrum_tmp, pstAuto_Scan->sfreq, ADC_sample_freq,loop_index);
            AUTOSCAN_PRINTF("time %d : Find TP number is %d\n",loop_index,TP_number);
        }
    }
    comm_free(channel_spectrum);
    comm_free(channel_spectrum_tmp);
    end_t=OS_GetTickCount();
    AUTOSCAN_PRINTF("\tSearch TP cost time %dms\n",end_t-temp_t);
    
#ifdef DEBUG_SOFT_SEARCH
    success=0;
    TP_number=1000;
    Bug_Freq[0]=1889824;///12446/V/1537
    Bug_Sym[0]=2062;
    Bug_Freq[1]=1762000;////12321/V/1500
    Bug_Sym[1]=1968;
    comm_memset(Frequency_Est, 0, sizeof(Frequency_Est));
    comm_memset(SymbolRate_Est, 0, sizeof(SymbolRate_Est));
    for(i=0;i<TP_number;i++)
    {
        Frequency_Est[i]=Bug_Freq[i%2];
        SymbolRate_Est[i]=Bug_Sym[i%2];
    }
#endif

    if(TP_number>0)
        success=0;
    AUTOSCAN_PRINTF("\\success = %d , TP_number = %d  \n",success,TP_number);
    if (success==0)
    {
        last_lock_freq = 0;
        last_lock_rs = 0;
        last_tp_freq=0;
        Final_Est_Freq=0;
        Final_Est_SymRate=0;
        for (i=0;i<TP_number;i++)
        {
            AUTOSCAN_PRINTF("\n\n----> Try %d-th TP [freq,Sym]=[%d, %d]\n",i,Frequency_Est[i],SymbolRate_Est[i]);
            if (priv->ul_status.s3501_autoscan_stop_flag)
            {
                AUTOSCAN_PRINTF("\tleave fuction nim_s3503_autoscan\n");
                return SUCCESS;
            }
#ifdef DEBUG_SOFT_SEARCH
            priv->ul_status.m_CRNum = 1;
            priv->ul_status.m_Freq[0] = Frequency_Est[i];
            priv->ul_status.m_Rs[0] = SymbolRate_Est[i];
#else
            if(Frequency_Est[i]/1024<945)
                continue;
            if(Frequency_Est[i]/1024>2155)
                continue;
            temp_t=OS_GetTickCount();
            temp_freq = (Frequency_Est[i]+512)/1024-last_lock_freq;
            if(temp_freq==0)    continue;
            if (temp_freq<0)
                temp_freq = -temp_freq;
            if ((SymbolRate_Est[i]+1000)/2000>temp_freq)
                continue;
            if ((last_lock_rs+1000)/2000>(UINT32)temp_freq)
                continue;
            priv->ul_status.m_CRNum = 1;
            priv->ul_status.m_Freq[0] = Frequency_Est[i];
            priv->ul_status.m_Rs[0] = SymbolRate_Est[i];
#endif
            if (SUCCESS == nim_s3503_channel_search(dev, 0))
            {
                AUTOSCAN_PRINTF("Find %d-th TP ---> SUCCESS!\n",i);
                nim_s3503_get_code_rate(dev, &cur_fec);
                cur_freq=Final_Est_Freq;
                cur_sym=	Final_Est_SymRate;
                last_lock_freq = cur_freq;
                last_lock_rs = cur_sym;
                if ((cur_freq >= pstAuto_Scan->sfreq) && (cur_freq <= pstAuto_Scan->efreq))
                {
                    if (pstAuto_Scan->unicable) //cur_freq -> [950, 2150]
                    {
                        AUTOSCAN_PRINTF("\tUnicable FFT_freq: %d, cur_freq: %d, Fub: %d\n", FFT_freq, cur_freq, pstAuto_Scan->Fub);
                        ret = pstAuto_Scan->callback(1, 0, FFT_freq + cur_freq - pstAuto_Scan->Fub, cur_sym, cur_fec);
                    }
                    else
                    {
                        if((cur_freq>last_tp_freq-2)&&(cur_freq<last_tp_freq+2))
                        {
                            ret = pstAuto_Scan->callback(0, 0, Frequency_Est[i]/1024, 0, 0);
                            AUTOSCAN_PRINTF("\tRescan a tp: FFT_freq: %d, last_tp_freq: %d\n", Frequency_Est[i]/1024, last_tp_freq);
                        }
                        else
                        {
                            ret = pstAuto_Scan->callback(1, 0, cur_freq, cur_sym, cur_fec);
                            last_tp_freq=cur_freq;
                        }
                    }
                }
                else
                {
                    if (priv->ul_status.s3501_autoscan_stop_flag)
                    {
                        AUTOSCAN_PRINTF("\tleave fuction nim_s3503_autoscan\n");
                        return SUCCESS;
                    }
                    else
                    {
                        continue ;
                    }
                }
            }
            else
            {
                ret = pstAuto_Scan->callback(0, 0, Frequency_Est[i]/1024, 0, 0);
            }
            if (ret == 2)
            {
                return SUCCESS;
            }
            else if (ret == 1)
            {
                goto nim_as_break;
            }
            end_t=OS_GetTickCount();
            AUTOSCAN_PRINTF("\tTP %d cost time %dms\n",i,end_t-temp_t);
        }
    }

#ifdef AUTOSCAN_DEBUG
    priv->Tuner_Config_Data.QPSK_Config = config_data;
#endif
    end_t=OS_GetTickCount();
    AUTOSCAN_PRINTF("\tautoscan cost time   %d:%d   \n",(((end_t-start_t)+500)/1000/60),(((end_t-start_t)+500)/1000-(((end_t-start_t)+500)/1000/60)*60));
    NIM_PRINTF("\tfinish autoscan\n");
    return SUCCESS;
    nim_as_break:
    pstAuto_Scan->callback(2, 0, 0, 0, 0);  /* Tell callback search finished */
    return ret;
}

 /*****************************************************************************
*INT32 nim_s3503_ioctl_ext(struct nim_device *dev, INT32 cmd, void *param_list)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
INT32 nim_s3503_ioctl_ext(struct nim_device *dev, INT32 cmd, void *param_list)
{
    nim_get_fft_result_t *fft_para;
    nim_diseqc_operate_para_t *diseqc_para;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
    UINT32 i;
    INT32 result=SUCCESS;
   UINT32 v_scan_loop=0x01;
	NIM_PRINTF("    Enter fuction nim_s3501_event_control\n");

	switch (cmd)
	{
	case NIM_DRIVER_AUTO_SCAN:
		/* Do AutoScan Procedure */
		#ifdef NIM_S3501_ASCAN_TOOLS
		//v_scan_loop= vs_s3501_ascan.va_ascan_g8_loop_cnt;// add code to set autoscan loop count
		//vs_s3501_ascan.va_ascan_g8_loop_cur_idx=0x00;
		#endif
			#ifdef NIM_S3501_ASCAN_TOOLS
			ascan_stop_flag=0x00;
			#endif
			NIM_PRINTF(">>>[JIE] NIM_DRIVER_AUTO_SCAN\n");
			result=nim_s3503_autoscan(dev, (struct NIM_Auto_Scan *) (param_list));
				#ifdef NIM_S3501_ASCAN_TOOLS
				if(priv->ul_status.s3501_autoscan_stop_flag)
					ascan_stop_flag=0x01;
				else
					nim_s3501_ascan_tps_lock_check();
				#endif
		return result;

	case NIM_DRIVER_CHANNEL_CHANGE:
		/* Do Channel Change */
		NIM_PRINTF(">>>[JIE] NIM_DRIVER_CHANNEL_CHANGE\n");
		{
			struct NIM_Channel_Change *nim_param = (struct NIM_Channel_Change *) (param_list);
			return nim_s3503_channel_change(dev, nim_param->freq, nim_param->sym, nim_param->fec);
		}
	case NIM_DRIVER_CHANNEL_SEARCH:
		/* Do Channel Search */
		break;
	case NIM_DRIVER_GET_ID:
		*((UINT32 *) param_list) = priv->ul_status.m_s3501_type;
		break;
    case NIM_DRIVER_GET_FFT_RESULT:
        fft_para = (nim_get_fft_result_t *)(param_list);
        return nim_s3503_get_fft_result(dev, fft_para->freq, fft_para->start_addr);
        break;
    case NIM_DRIVER_DISEQC_OPERATION:
        diseqc_para = (nim_diseqc_operate_para_t *)(param_list);
        return nim_s3503_DiSEqC_operate(dev, diseqc_para->mode, diseqc_para->cmd, diseqc_para->cnt);
        break;
    case NIM_DRIVER_DISEQC2X_OPERATION:
        diseqc_para = (nim_diseqc_operate_para_t *)(param_list);
        return nim_s3503_DiSEqC2X_operate(dev, diseqc_para->mode, diseqc_para->cmd, diseqc_para->cnt, \
            diseqc_para->rt_value, diseqc_para->rt_cnt);
        break;

	default:
		break;
	}

	return SUCCESS;
}

 /*****************************************************************************
* INT32 nim_s3503_get_bitmode(struct nim_device *dev, UINT8 *bitMode)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static  INT32 nim_s3503_get_bitmode(struct nim_device *dev, UINT8 *bitMode)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

	if ((priv->Tuner_Config_Data.QPSK_Config & 0xc0) == M3501_1BIT_MODE)
		*bitMode = 0x60;
	else if ((priv->Tuner_Config_Data.QPSK_Config & 0xc0) == M3501_2BIT_MODE)
		*bitMode = 0x00;
	else if ((priv->Tuner_Config_Data.QPSK_Config & 0xc0) == M3501_4BIT_MODE)
		*bitMode = 0x20;
	else if ((priv->Tuner_Config_Data.QPSK_Config & 0xc0) == M3501_8BIT_MODE)
		*bitMode = 0x40;
	else
		*bitMode = 0x40;
	return SUCCESS;
}


// begin add operation for s3501 optimize
 /*****************************************************************************
* static INT32 nim_s3503_set_err(struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_set_err(struct nim_device *dev)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	priv->ul_status.m_Err_Cnts++;
	return SUCCESS;
}

 /*****************************************************************************
* static INT32 nim_s3503_get_err(struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_get_err(struct nim_device *dev)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	if (priv->ul_status.m_Err_Cnts > 0x00)
		return ERR_FAILED;
	else
		return SUCCESS;
}

  /*****************************************************************************
* static INT32 nim_s3503_clear_err(struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_clear_err(struct nim_device *dev)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	priv->ul_status.m_Err_Cnts = 0x00;
	return SUCCESS;
}

  /*****************************************************************************
* static INT32 nim_s3503_get_type(struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_get_type(struct nim_device *dev)
{
	UINT8 temp[4] =
	{
		0x00, 0x00, 0x00, 0x00
	};
	UINT32 m_Value = 0x00;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	priv->ul_status.m_s3501_type = 0x00;
	nim_reg_read(dev, RA3_CHIP_ID, temp, 4);
	m_Value = temp[1];
	m_Value = (m_Value << 8) | temp[0];
	m_Value = (m_Value << 8) | temp[3];
	m_Value = (m_Value << 8) | temp[2];
	priv->ul_status.m_s3501_type = m_Value;
	nim_reg_read(dev, RA6_VER_SUB_ID, temp, 1); // if 1,C3503;else S3503
	if(temp[0] == 0x01)
		priv->ul_status.m_s3501_sub_type = NIM_C3503_SUB_ID;
       else
		priv->ul_status.m_s3501_sub_type = NIM_S3503_SUB_ID;
	return SUCCESS;
}


  /*****************************************************************************
* static INT32 nim_s3503_set_ext_LNB(struct nim_device *dev, struct QPSK_TUNER_CONFIG_API *ptrQPSK_Tuner)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_set_ext_LNB(struct nim_device *dev, struct QPSK_TUNER_CONFIG_API *ptrQPSK_Tuner)
{
	/****For external lnb controller config****/
	struct nim_s3501_private *priv_mem = (struct nim_s3501_private *) dev->priv;
	priv_mem->ext_lnb_control = NULL;
	if (ptrQPSK_Tuner->ext_lnb_config.ext_lnb_control)
	{
		UINT32 check_sum = 0;
		check_sum = (UINT32) (ptrQPSK_Tuner->ext_lnb_config.ext_lnb_control);
		check_sum += ptrQPSK_Tuner->ext_lnb_config.i2c_base_addr;
		check_sum += ptrQPSK_Tuner->ext_lnb_config.i2c_type_id;
		if (check_sum == ptrQPSK_Tuner->ext_lnb_config.param_check_sum)
		{
			priv_mem->ext_lnb_control = ptrQPSK_Tuner->ext_lnb_config.ext_lnb_control;
			priv_mem->ext_lnb_control(0, LNB_CMD_ALLOC_ID, (UINT32) (&priv_mem->ext_lnb_id));
			priv_mem->ext_lnb_control(priv_mem->ext_lnb_id, LNB_CMD_INIT_CHIP, (UINT32) (&ptrQPSK_Tuner->ext_lnb_config));
		}
	}

	return SUCCESS;
}

 /*****************************************************************************
* static INT32 nim_s3503_interrupt_mask_clean(struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_interrupt_mask_clean(struct nim_device *dev)
{
	UINT8 data = 0x00;
	nim_reg_write(dev, R02_IERR, &data, 1);
	data = 0xff;
	nim_reg_write(dev, R03_IMASK, &data, 1);
	return SUCCESS;
}

 /*****************************************************************************
* static INT32 nim_s3503_sym_config(struct nim_device *dev, UINT32 sym)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_sym_config(struct nim_device *dev, UINT32 sym)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	if (sym > 40000)
		priv->ul_status.c_RS = 8;
	else if (sym > 30000)
		priv->ul_status.c_RS = 4;
	else if (sym > 20000)
		priv->ul_status.c_RS = 2;
	else if (sym > 10000)
		priv->ul_status.c_RS = 1;
	else
		priv->ul_status.c_RS = 0;
	return SUCCESS;
}

 /*****************************************************************************
* static INT32 nim_s3503_set_adc(struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_set_adc(struct nim_device *dev)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	UINT8 data, ver_data;
	// ADC setting
	if (priv->Tuner_Config_Data.QPSK_Config & M3501_IQ_AD_SWAP)
		data = 0x4a;
	else
		data = 0x0a;
	if (priv->Tuner_Config_Data.QPSK_Config & M3501_EXT_ADC)
		data |= 0x80;
	else
		data &= 0x7f;
	nim_reg_write(dev, R01_ADC, &data, 1);

	nim_reg_read(dev, R01_ADC, &ver_data, 1);
	if (data != ver_data)
	{
		NIM_PRINTF(" wrong 0x8 reg write\n");
		return ERR_FAILED;
	}

	return SUCCESS;
}

 /*****************************************************************************
* static INT32 nim_s3503_set_hw_timeout(struct nim_device *dev, UINT8 time_thr)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_set_hw_timeout(struct nim_device *dev, UINT8 time_thr)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

	// AGC1 setting
	if (time_thr != priv->ul_status.m_hw_timeout_thr)
	{
		nim_reg_write(dev, R05_TIMEOUT_TRH, &time_thr, 1);
		priv->ul_status.m_hw_timeout_thr = time_thr;
	}

	return SUCCESS;
}

 /*****************************************************************************
* static INT32 nim_s3503_set_agc1(struct nim_device *dev, UINT8 low_sym, UINT8 s_Case)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_set_agc1(struct nim_device *dev, UINT8 low_sym, UINT8 s_Case)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	UINT8 data;

	// AGC1 setting
	if (priv->Tuner_Config_Data.QPSK_Config & M3501_NEW_AGC1)
	{
	  switch (s_Case)
	  {
		case NIM_OPTR_CHL_CHANGE:
			if (1 == low_sym)
				data = 0xaf;
			else
				data = 0xb5;
			break;
		case NIM_OPTR_SOFT_SEARCH:
			if (1 == low_sym)
				data = 0xb3;//0xb1;
			else
				data = 0xba;//0xb9;
			break;
		case NIM_OPTR_FFT_RESULT:
                data=0xb9;
			break;
		}
	}
	else
	{
	  switch (s_Case)
	  {
		case NIM_OPTR_CHL_CHANGE:
		case NIM_OPTR_SOFT_SEARCH:
			if (1 == low_sym)
				data = 0x3c;
			else
				data = 0x54;
			break;
		case NIM_OPTR_FFT_RESULT:
			data = 0x54;
			break;
	  }
	}
	if ((priv->Tuner_Config_Data.QPSK_Config & M3501_AGC_INVERT) == 0x0)  // STV6110's AGC be invert by QinHe
		data = data ^ 0x80;

	nim_reg_write(dev, R07_AGC1_CTRL, &data, 1);

	data = 0x58;
	nim_reg_write(dev, R07_AGC1_CTRL+0x01, &data, 1);
       data = 0x50; 
       nim_reg_write(dev, R0A_AGC1_LCK_CMD, &data, 1);	

	return SUCCESS;
}

 /*****************************************************************************
* static INT32 nim_s3503_freq_offset_set(struct nim_device *dev, UINT8 low_sym, UINT32 *s_Freq)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_freq_offset_set(struct nim_device *dev, UINT8 low_sym, UINT32 *s_Freq)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

	if (priv->Tuner_Config_Data.QPSK_Config & M3501_QPSK_FREQ_OFFSET)
	{
		if (1 == low_sym)
			*s_Freq += 3;
	}
	return SUCCESS;
}

 /*****************************************************************************
* static INT32 nim_s3503_freq_offset_reset(struct nim_device *dev, UINT8 low_sym)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_freq_offset_reset(struct nim_device *dev, UINT8 low_sym)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

	if (priv->Tuner_Config_Data.QPSK_Config & M3501_QPSK_FREQ_OFFSET)
	{
		if (1 == low_sym)
			nim_s3503_set_freq_offset(dev, -3000);
		else
			nim_s3503_set_freq_offset(dev, 0);
	}
	else
		nim_s3503_set_freq_offset(dev, 0);

	return SUCCESS;
}

 /*****************************************************************************
* static INT32 nim_s3503_freq_offset_reset1(struct nim_device *dev, UINT8 low_sym, INT32 delfreq)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_freq_offset_reset1(struct nim_device *dev, UINT8 low_sym, INT32 delfreq)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

	if (priv->Tuner_Config_Data.QPSK_Config & M3501_QPSK_FREQ_OFFSET)
	{
		if (1 == low_sym)
			nim_s3503_set_freq_offset(dev, -3000 + delfreq);
		else
			nim_s3503_set_freq_offset(dev, delfreq);
	}
	else
		nim_s3503_set_freq_offset(dev, delfreq);

	return SUCCESS;
}

 /*****************************************************************************
* static INT32 nim_s3503_tr_setting(struct nim_device *dev, UINT8 s_Case)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_tr_setting(struct nim_device *dev, UINT8 s_Case)
 {
	return SUCCESS;
 }


 /*****************************************************************************
* static INT32 nim_s3503_cr_setting(struct nim_device *dev, UINT8 s_Case)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_cr_setting(struct nim_device *dev, UINT8 s_Case)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	UINT8 data;
	switch (s_Case)
	{
    	case NIM_OPTR_SOFT_SEARCH:
    		// set CR parameter
				nim_reg_read(dev, RE0_PPLL_CTRL, &data, 1);
				data = data|0x08;     ///force old CR
				nim_reg_write(dev, RE0_PPLL_CTRL, &data, 1);
				
    		data = 0xaa;
    		nim_reg_write(dev, R33_CR_CTRL + 0x03, &data, 1);
    		data = 0x45;
    		nim_reg_write(dev, R33_CR_CTRL + 0x04, &data, 1);
    		data = 0x97;
    		nim_reg_write(dev, R33_CR_CTRL + 0x05, &data, 1);
    		data = 0x87;
    		nim_reg_write(dev, RB5_CR_PRS_TRA, &data, 1);
    		break;
    	case NIM_OPTR_CHL_CHANGE:
    		// set CR parameter
    		nim_reg_read(dev, RE0_PPLL_CTRL, &data, 1);
				data = data&0xf7;    ///disable old CR
				nim_reg_write(dev, RE0_PPLL_CTRL, &data, 1);
				
    		data = 0xaa;
    		nim_reg_write(dev, R33_CR_CTRL + 0x03, &data, 1);
    		data = 0x4a;
    		nim_reg_write(dev, R33_CR_CTRL + 0x04, &data, 1);
            data = 0x86;
    		nim_reg_write(dev, R33_CR_CTRL + 0x05, &data, 1);
    		data = 0x88; 
    		nim_reg_write(dev, RB5_CR_PRS_TRA, &data, 1);
    		break;
    	default:
    		NIM_PRINTF(" CMD for nim_s3503_cr_setting ERROR!!!");
    		break;
	}

	return SUCCESS;
}
/*****************************************************************************
* static INT32 nim_s3503_ldpc_keep_working_enable(struct nim_device *dev)
* Description: set ldpc to work until a new frame start
*  Arguments:
*  Parameter1: struct nim_device *dev
* Return Value: INT32
*****************************************************************************/

static INT32 nim_s3503_ldpc_keep_working_enable(struct nim_device *dev)
{
   UINT8 data;
   nim_reg_read(dev, R12d_LDPC_SEL, &data, 1);
    data |= 0x40;
    nim_reg_write(dev, R12d_LDPC_SEL, &data, 1);

    return SUCCESS;
}

/*****************************************************************************
* static INT32 nim_s3503_ldpc_keep_working_disable(struct nim_device *dev)
* Description: set ldpc back to the normal mode
*  Arguments:
*  Parameter1: struct nim_device *dev
* Return Value: INT32
*****************************************************************************/

static INT32 nim_s3503_ldpc_keep_working_disable(struct nim_device *dev)
{
   UINT8 data;
   nim_reg_read(dev, R12d_LDPC_SEL, &data, 1);
    data &= 0xbf;
    nim_reg_write(dev, R12d_LDPC_SEL, &data, 1);

    return SUCCESS;
}

 /*****************************************************************************
* static INT32 nim_s3503_fec_set_ldpc(struct nim_device *dev, UINT8 s_Case, UINT8 c_ldpc, UINT8 c_fec)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_set_ldpc_iter_para(struct nim_device *dev, UINT16 most_cnt, UINT8 least_cnt, UINT8 exit_cnt_thld)
{
	UINT8 data, temp;

    data = (UINT8) most_cnt&0xff;
    nim_reg_write(dev, R57_LDPC_CTRL, &data, 1);
    
    temp = (UINT8) ( (most_cnt>>8)&0x03 );
    temp <<= 4;
    nim_reg_read(dev, RC1_DVBS2_FEC_LDPC, &data, 1);
    data |= temp;
    nim_reg_write(dev, RC1_DVBS2_FEC_LDPC, &data, 1);

    nim_reg_read(dev, R57_LDPC_CTRL+1, &data, 1);
    temp = least_cnt & 0x3f;
    data |= temp;
    nim_reg_write(dev, R57_LDPC_CTRL+1, &data, 1);

    nim_reg_read(dev, R57_LDPC_CTRL+2, &data, 1);
    temp = exit_cnt_thld & 0x3f;
    data |= temp;
    nim_reg_write(dev, R57_LDPC_CTRL+2, &data, 1);
    
	return SUCCESS;
}
 /*****************************************************************************
* static INT32 nim_s3503_fec_set_ldpc(struct nim_device *dev, UINT8 s_Case, UINT8 c_ldpc, UINT8 c_fec)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_fec_set_ldpc(struct nim_device *dev, UINT8 s_Case, UINT8 c_ldpc, UINT8 c_fec)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	UINT8 data;
	UINT8 temp[3]={0xff, 0xc8, 0x08};
	// LDPC parameter
	switch (s_Case)
	{
	   case NIM_OPTR_CHL_CHANGE:
		    nim_reg_write(dev, R57_LDPC_CTRL, temp, 3);
            data = 0x30; // disactive ldpc avg iter and ldpc_max_iter_num[9:8]=0x3
	        nim_reg_write(dev, RC1_DVBS2_FEC_LDPC, &data, 1);
		break;
	    case NIM_OPTR_SOFT_SEARCH:
		    temp[1] =  0x48;
		    nim_reg_write(dev, R57_LDPC_CTRL, temp, 3);
		    data = 0x30; 
		    nim_reg_write(dev, RC1_DVBS2_FEC_LDPC, &data, 1);
		break;
	    default:
		    NIM_PRINTF(" CMD for nim_s3503_fec_set_ldpc ERROR!!!");
		break;
	}
	return SUCCESS;
}

 /*****************************************************************************
* static INT32 nim_s3503_hw_init(struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_hw_init(struct nim_device *dev)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	UINT8 data ;
	UINT32 data_tmp;

	// set TR lock symbol number thr, k unit.
	data = 0x1f; // setting for soft search function
	nim_reg_write(dev, R1B_TR_TIMEOUT_BAND, &data, 1);

	// Carcy change PL time out, for low symbol rate. 2008-03-12
	data = 0x84;
	nim_reg_write(dev, R28_PL_TIMEOUT_BND + 0x01, &data, 1);

	// Set Hardware time out
	//data = 0xff;
	//nim_reg_write(dev,R05_TIMEOUT_TRH, &data, 1);
	nim_s3503_set_hw_timeout(dev, 0xff);

	//----eq demod setting
	// Open EQ controll for QPSK and 8PSK
	data = 0x04;		//  set EQ control
	nim_reg_write(dev, R21_BEQ_CTRL, &data, 1);

	data = 0x24;		//  set EQ mask mode, mask EQ for 1/4,1/3,2/5 code rate
	nim_reg_write(dev, R25_BEQ_MASK, &data, 1);

	// Carcy add for 16APSK
	data = 0x6c;
	nim_reg_write(dev, R2A_PL_BND_CTRL + 0x02, &data, 1);
	//----eq demod setting end
	
	data = 0x81;
	nim_reg_write(dev, RFA_RESET_CTRL, &data, 1);

	nim_s3503_set_adc(dev);

	if ((priv->Tuner_Config_Data.QPSK_Config & 0xc0) == M3501_8BIT_MODE)
	nim_s3503_tso_initial (dev, 1, 1);
	else if ((priv->Tuner_Config_Data.QPSK_Config & 0xc0) == M3501_1BIT_MODE)
	nim_s3503_tso_initial (dev, 1, 0);

    nim_s3503_DiSEqC_initial(dev);
	nim_s3503_cr_adaptive_initial(dev);

	data = 0xe1;
	nim_reg_write(dev, RDC_EQ_DBG_TS_CFG, &data, 1);
// For C3503 only
    if(priv->ul_status.m_s3501_sub_type == NIM_C3503_SUB_ID)
    {
    	nim_reg_read (dev, RF1_DSP_CLK_CTRL, &data, 1);
    	data = data | 0x08; // enable DVBS/S2 FEC clock gate.
    	data = data | 0x10; // enable mdo_cnt_clean with sync
    	nim_reg_write(dev, RF1_DSP_CLK_CTRL, &data, 1);
   	}
    
    // For C3503 new CR only
    if(priv->ul_status.m_s3501_sub_type == NIM_C3503_SUB_ID)
    {
	  nim_s3503_cr_new_tab_init(dev);
      nim_s3503_cr_adaptive_method_choice(dev,0); //0:new;1:old;2:both;3:register  
      // enable MERGE_ROUND 
      nim_reg_read(dev,0x137,&data,1);
      data |=0x20; 
      nim_reg_write(dev,0x137,&data,1);    
    }


 // For C3503 FEC only
    if(priv->ul_status.m_s3501_sub_type == NIM_C3503_SUB_ID)
    {          
        #ifdef INIT_32APSK_TARGET
            nim_s3503_set_32apsk_target(dev);
        #endif
        nim_reg_read(dev,0xb4,&data,1);
        data &=0x8f;
        data |=0x10;// CENTRAL_UPDATE_STEP =1
        nim_reg_write(dev,0xb4,&data,1);
        
        nim_reg_read(dev,0x21,&data,1);
        data &=0x1f;
        data |=0x20;// OTHER_UPDATE_STEP =1
        nim_reg_write(dev,0x21,&data,1);

      // add by hongyu for ldpc maximum iteration
        data=0xff;
        nim_reg_write(dev,R57_LDPC_CTRL,&data,1);
        nim_reg_read(dev,0xc1,&data,1);
        data &= 0xfe; //disable LDPC_AVG_ITER_ACT
        data |=0x30; // ldpc_max_iter_num[9:8]=0x3
        nim_reg_write(dev,0xc1,&data,1);      
    }
    
	return SUCCESS;
}

 /*****************************************************************************
* static INT32 nim_s3503_set_demod_ctrl(struct nim_device *dev, UINT8 c_Value)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_set_demod_ctrl(struct nim_device *dev, UINT8 c_Value)
{
	UINT8 data = c_Value;
	nim_reg_write(dev, R00_CTRL, &data, 1);
	return SUCCESS;
}

 /*****************************************************************************
* static INT32 nim_s3503_set_hbcd_timeout(struct nim_device *dev, UINT8 s_Case)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_set_hbcd_timeout(struct nim_device *dev, UINT8 s_Case)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	UINT8 data;
	switch (s_Case)
	{
	case NIM_OPTR_CHL_CHANGE:
	case NIM_OPTR_IOCTL:
		if (priv->t_Param.t_reg_setting_switch & NIM_SWITCH_HBCD)
		{
			if (priv->ul_status.m_enable_dvbs2_hbcd_mode)
				data = priv->ul_status.m_dvbs2_hbcd_enable_value;
			else
				data = 0x00;
			nim_reg_write(dev, R47_HBCD_TIMEOUT, &data, 1);
			priv->t_Param.t_reg_setting_switch &= ~NIM_SWITCH_HBCD;
		}
		break;
	case NIM_OPTR_SOFT_SEARCH:
		if (!(priv->t_Param.t_reg_setting_switch & NIM_SWITCH_HBCD))
		{
			data = 0x00;
			nim_reg_write(dev, R47_HBCD_TIMEOUT, &data, 1);
			priv->t_Param.t_reg_setting_switch |= NIM_SWITCH_HBCD;
		}
		break;
	case NIM_OPTR_HW_OPEN:
		nim_reg_read(dev, R47_HBCD_TIMEOUT, &(priv->ul_status.m_dvbs2_hbcd_enable_value), 1);
		break;
	default:
		NIM_PRINTF(" CMD for nim_s3503_set_hbcd_timeout ERROR!!!");
		break;
	}
	return SUCCESS;
}

 /*****************************************************************************
* static INT32 nim_s3503_set_acq_workmode(struct nim_device *dev, UINT8 s_Case)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_set_acq_workmode(struct nim_device *dev, UINT8 s_Case)
{
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	UINT8 data, work_mode = 0x00;
	switch (s_Case)
	{
	case NIM_OPTR_CHL_CHANGE0:
	case NIM_OPTR_DYNAMIC_POW0:
        	data = 0x73;
		nim_reg_write(dev, R5B_ACQ_WORK_MODE, &data, 1);
		break;
	case NIM_OPTR_CHL_CHANGE:
		nim_s3503_reg_get_work_mode(dev, &work_mode);
		if (work_mode != M3501_DVBS2_MODE)// not in DVBS2 mode, key word: power_ctrl
		{
			priv->ul_status.phase_err_check_status = 1000;
			// slow down S2 clock
			data = 0x77;
			nim_reg_write(dev, R5B_ACQ_WORK_MODE, &data, 1);
		}
		break;
	case NIM_OPTR_SOFT_SEARCH:
		data = 0x77;
		nim_reg_write(dev, R5B_ACQ_WORK_MODE, &data, 1);
		break;
	case NIM_OPTR_HW_OPEN:
			// enable ADC
			data = 0x00;
			nim_reg_write(dev, RA0_RXADC_REG + 0x02, &data, 1);
			// enable S2 clock
			data = 0x73;
			nim_reg_write(dev, R5B_ACQ_WORK_MODE, &data, 1);
		break;
	case NIM_OPTR_HW_CLOSE:
			// close ADC
			data = 0x07;
			nim_reg_write(dev, RA0_RXADC_REG + 0x02, &data, 1);
			// close S2 clock
			data = 0x3f;
		nim_reg_write(dev, R5B_ACQ_WORK_MODE, &data, 1);
		break;
	default:
		NIM_PRINTF(" CMD for nim_s3503_set_acq_workmode ERROR!!!");
		break;
	}
	return SUCCESS;
}

 /*****************************************************************************
* static INT32 nim_s3503_set_FC_Search_Range(struct nim_device *dev, UINT8 s_Case, UINT32 rs)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_set_FC_Search_Range(struct nim_device *dev, UINT8 s_Case, UINT32 rs)
{
    struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
    UINT8 data, ver_data;
    UINT32 temp;
    UINT32 sample_rate;

    nim_s3503_get_dsp_clk (dev, &sample_rate);
    sample_rate=((sample_rate+500)/1000);
    switch (s_Case)
    {
        case NIM_OPTR_SOFT_SEARCH:
        {
            if (rs > 18000)
                temp = 5 * 16; 
            else if (rs > 15000)
                temp = 4 * 16;
            else if (rs > 10000)
                temp = 3 * 16;
            else if (rs > 5000)
                temp = 2 *16;
            else
                temp = 1 *16;
            data = temp & 0xff;
            nim_reg_write(dev, R62_FC_SEARCH, &data, 1);
            data = (temp >> 8) & 0x3;
            if (rs > 10000)
                data |= 0xa0;	// amy change for 138E 12354V43000 est 1756/37333
            else if (rs > 5000)
                data |= 0xc0;   	//amy change for 91.5E 3814/V/6666
            else
                data |= 0xb0;   	//amy change for 91.5E 3629/V/2200
			nim_reg_write(dev, R62_FC_SEARCH + 0x01, &data, 1);
			priv->t_Param.t_reg_setting_switch |= NIM_SWITCH_FC;
        }
            break;
        case NIM_OPTR_CHL_CHANGE:
            //if (priv->t_Param.t_reg_setting_switch & NIM_SWITCH_FC)
            {
    			// set sweep range
    			//temp = (3 * 90 * 16+sample_rate/2) / sample_rate;
                if (rs > 18000)
                    temp = 5 * 16; 
                else if (rs > 15000)
                    temp = 4 * 16;
                else if (rs > 4000)
                    temp = 3 * 16;
                else
                    temp = 2 *16;

    			data = temp & 0xff;
    			nim_reg_write(dev, R62_FC_SEARCH, &data, 1);
    			data = (temp >> 8) & 0x3;
    			data |= 0xb0;
    			nim_reg_write(dev, R62_FC_SEARCH + 0x01, &data, 1);
    			priv->t_Param.t_reg_setting_switch &= ~NIM_SWITCH_FC;
            }
            break;
        default:
            NIM_PRINTF(" CMD for nim_s3503_set_FC_Search_Range ERROR!!!");
            break;
    }
	return SUCCESS;
}

 /*****************************************************************************
* static INT32 nim_s3503_set_RS_Search_Range(struct nim_device *dev, UINT8 s_Case, UINT32 rs)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_set_RS_Search_Range(struct nim_device *dev, UINT8 s_Case, UINT32 rs)
{
    struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
    UINT8 data, ver_data;
    UINT32 sample_rate;
    UINT32 temp;
        
    nim_s3503_get_dsp_clk (dev, &sample_rate);
    sample_rate=((sample_rate+500)/1000);

    switch (s_Case)
    {
        case NIM_OPTR_SOFT_SEARCH:
            {
                temp =(rs+1000) / 2000;
    			if (temp < 2)
    				temp = 2;
    			else if (temp > 11)
    				temp = 11;
    			temp = temp << 4;
    			data = temp & 0xff;
    			nim_reg_write(dev, R64_RS_SEARCH, &data, 1); ////CR64
    			data = (temp >> 8) & 0x3;
    			data |= 0xa0;		////RS_Search_Step=2
    			nim_reg_write(dev, R64_RS_SEARCH + 0x01, &data, 1);////CR65
    			priv->t_Param.t_reg_setting_switch |= NIM_SWITCH_RS;
            }
            break;
        case NIM_OPTR_CHL_CHANGE:
            if (priv->t_Param.t_reg_setting_switch & NIM_SWITCH_RS)
            {
                temp = (3 * 90 * 16+sample_rate/2) /sample_rate;
                data = temp & 0xff;
                nim_reg_write(dev, R64_RS_SEARCH, &data, 1);
                data = (temp >> 8) & 0x3;
                data |= 0x30;
                nim_reg_write(dev, R64_RS_SEARCH + 0x01, &data, 1);
                priv->t_Param.t_reg_setting_switch &= ~NIM_SWITCH_RS;
            }
            break;
        default:
            NIM_PRINTF(" CMD for nim_s3503_set_RS_Search_Range ERROR!!!");
            break;
    }
	return SUCCESS;
}

 /*****************************************************************************
* static INT32 nim_s3503_cap_IQ_enerage(struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_cap_IQ_enerage(struct nim_device *dev)
{
	UINT8 data = 0;
	UINT8 buffer[8];
	INT32 i = 0, j = 0, k = 0;
	UINT8 fft_data[3];
	INT32 fft_I, fft_Q;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;

	for (i = 0; i < 1024; i++)
	{
		data = (UINT8) ((i) & 0xff);
		buffer[0] = data;
		data = (UINT8) (i >> 8);
		data &= 0x3;
		buffer[1] = data;
		nim_reg_write(dev, R70_CAP_REG, buffer, 2);
		nim_reg_read(dev, R70_CAP_REG + 0x02, fft_data, 2);

		fft_I = fft_data[0];
		fft_Q = fft_data[1];

		if (fft_I & 0x80)
			fft_I |= 0xffffff00;
		if (fft_Q & 0x80)
			fft_Q |= 0xffffff00;

		k = 0;
		for (j = 0; j < 10; j++)
		{
			k <<= 1;k += ((i >> j) & 0x1);
		}//address change for 1024 FFT

		fft_I = fft_I << (FFT_BITWIDTH - 8);
		fft_Q = fft_Q << (FFT_BITWIDTH - 8);

		priv->ul_status.FFT_I_1024[k] = fft_I;
		priv->ul_status.FFT_Q_1024[k] = fft_Q;
	}
if(1==S3503_Debug_Flag&&(0x01))
{
for(i = 0; i< 1024; i++)
{
	AUTOSCAN_PRINTF("ADCdata%d:[%d,%d]\n",i,priv->ul_status.FFT_I_1024[i] ,priv->ul_status.FFT_Q_1024[i]);
}
}
	return SUCCESS;
}

 /*****************************************************************************
* static INT32 nim_s3503_TR_CR_Setting(struct nim_device *dev, UINT8 s_Case)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_TR_CR_Setting(struct nim_device *dev, UINT8 s_Case)
{
	UINT8 data = 0;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	switch (s_Case)
	{
	case NIM_OPTR_SOFT_SEARCH:
	//	if (!(priv->t_Param.t_reg_setting_switch & NIM_SWITCH_TR_CR))
		{
			data = 0x49;//0x4d;
			nim_reg_write(dev, R66_TR_SEARCH, &data, 1);
			data = 0x31;
			nim_reg_write(dev, R67_VB_CR_RETRY, &data, 1);
	//		priv->t_Param.t_reg_setting_switch |= NIM_SWITCH_TR_CR;
		}
		break;
	case NIM_OPTR_CHL_CHANGE:
		if (priv->t_Param.t_reg_setting_switch & NIM_SWITCH_TR_CR)
		{
			// set reg to default value
			data = 0x59;
			nim_reg_write(dev, R66_TR_SEARCH, &data, 1);
			data = 0x33;
			nim_reg_write(dev, R67_VB_CR_RETRY, &data, 1);
			priv->t_Param.t_reg_setting_switch &= ~NIM_SWITCH_TR_CR;
		}
		break;
	}
	return SUCCESS;
}

  /*****************************************************************************
* static INT32 nim_s3503_task_init(struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_task_init(struct nim_device *dev)
{
	UINT8 nim_device[3][3] =
	{
		'N', 'M', '0', 'N', 'M', '1', 'N', 'M', '2'
	};
	//ID				  nim_task_id ;//= OSAL_INVALID_ID;
	//T_CTSK	 t_ctsk;
	T_CTSK nim_task_praram;
	static UINT8 nim_task_num = 0x00;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	INT32 ret = 0 ;
	if (nim_task_num > 1)
		return SUCCESS;

	nim_task_praram.task = nim_s3503_task;//dmx_m3327_record_task ;
	nim_task_praram.name[0] = nim_device[nim_task_num][0];
	nim_task_praram.name[1] = nim_device[nim_task_num][1];
	nim_task_praram.name[2] = nim_device[nim_task_num][2];
	nim_task_praram.stksz = 0xc00 ;
	nim_task_praram.itskpri = OSAL_PRI_NORMAL;
	nim_task_praram.quantum = 10 ;
	nim_task_praram.para1 = (UINT32) dev ;
	nim_task_praram.para2 = 0 ;//Reserved for future use.
	priv->tsk_status.m_task_id = osal_task_create(&nim_task_praram);
	if (OSAL_INVALID_ID == priv->tsk_status.m_task_id)
	{
		//NIM_PRINTF("Task create error\n");
		return OSAL_E_FAIL;
	}
	nim_task_num++;

	return SUCCESS;
}

  /*****************************************************************************
* static void nim_s3503_task(UINT32 param1, UINT32 param2)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static void nim_s3503_task(UINT32 param1, UINT32 param2)
{
	struct nim_device *dev = (struct nim_device *) param1 ;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv ;
	priv->tsk_status.m_sym_rate = 0x00;
	priv->tsk_status.m_code_rate = 0x00;
	priv->tsk_status.m_map_type = 0x00;
	priv->tsk_status.m_work_mode = 0x00;
	priv->tsk_status.m_info_data = 0x00;
	NIM_PRINTF("            Enter nim task \n");
	UINT32 v_cnt_val=0x00;
    UINT32 rpt_carr_offset;
    UINT8 rdata[3];
    UINT8 step;
    UINT8 nframe;
    UINT8 data;
    UINT8 data_temp;
#ifdef CHANNEL_CHANGE_ASYNC
	UINT32 flag_ptn;
#endif

	while (1)
	{
#ifdef CHANNEL_CHANGE_ASYNC
		flag_ptn = 0;
		if (NIM_FLAG_WAIT(&flag_ptn, priv->flag_id, NIM_FLAG_CHN_CHG_START, OSAL_TWF_ANDW | OSAL_TWF_CLR, 0) == OSAL_E_OK)
		{
			//osal_flag_clear(priv->flag_id, NIM_FLAG_CHN_CHG_START);
			NIM_FLAG_SET(priv->flag_id, NIM_FLAG_CHN_CHANGING);
			osal_mutex_lock(priv->m3501_mutex,OSAL_WAIT_FOREVER_TIME);
			nim_s3503_waiting_channel_lock(dev, priv->cur_freq, priv->cur_sym);
			osal_mutex_unlock(priv->m3501_mutex);
			NIM_FLAG_CLEAR(priv->flag_id, NIM_FLAG_CHN_CHANGING);
			NIM_PRINTF("\t\t Here is the task for M3501C wait channel lock \n");
		}
#endif

			if(priv->tsk_status.m_lock_flag == NIM_LOCK_STUS_CLEAR)
			{
				if(v_cnt_val  == 30)
				{
					v_cnt_val = 0;
					NIM_PRINTF("\t\t Here is the task for M3501C plug_in_out \n");
                    nim_s3503_debug_intask(dev);
				}
				else
					v_cnt_val ++;
			}
			else
			{
				if ((priv->tsk_status.m_lock_flag == NIM_LOCK_STUS_SETTING) && (priv->t_Param.t_i2c_err_flag == 0x00))
				{
					nim_s3503_get_lock(dev, &(priv->tsk_status.m_info_data));
					if (priv->tsk_status.m_info_data && (priv->t_Param.t_i2c_err_flag == 0x00))
					{
						nim_s3503_reg_get_symbol_rate(dev, &(priv->tsk_status.m_sym_rate));
						nim_s3503_reg_get_code_rate(dev, &(priv->tsk_status.m_code_rate));
						nim_s3503_reg_get_work_mode(dev, &(priv->tsk_status.m_work_mode));
						nim_s3503_reg_get_map_type(dev, &(priv->tsk_status.m_map_type));
						if ((priv->ul_status.m_enable_dvbs2_hbcd_mode == 0) &&
							((priv->tsk_status.m_map_type == 0) || (priv->tsk_status.m_map_type == 5)))
						{
							NIM_PRINTF("            Demod Error: wrong map_type is %d\n", priv->tsk_status.m_map_type);
						}
						else
						{
							nim_s3503_interrupt_clear(dev);
							priv->tsk_status.m_lock_flag = NIM_LOCK_STUS_CLEAR;
						}
					}
				}
			}

            nim_reg_read(dev, RF8_MODCOD_RPT, &data, 1);
            data = data & 0x7f;
            nim_reg_read(dev, R04_STATUS, &data_temp, 1);
            if( (modcod_temp!=data)&&(data_temp==0x7f))
            {
                modcod_temp=data;
                nim_s3503_set_demod_ctrl(dev, NIM_DEMOD_CTRL_0X91);
                nim_s3503_set_demod_ctrl(dev, NIM_DEMOD_CTRL_0X51);    
            }

            
 // For C3503 only
    if((priv->ul_status.m_s3501_sub_type == NIM_C3503_SUB_ID)&&(AutoScan_or_ChannelChange==1))
    {                   
          nim_s3503_cr_new_adaptive_unlock_monitor(dev);
          nim_s3503_NframeStepTso_setting(dev,100,0x00);
      /*    nim_reg_read(dev,0x69,rdata,3);
          rpt_carr_offset = rdata[2] & 0x01;
          rpt_carr_offset = rpt_carr_offset << 8;
          rpt_carr_offset = rpt_carr_offset | rdata[1];
          rpt_carr_offset = rpt_carr_offset << 8;
          rpt_carr_offset = rpt_carr_offset | rdata[0];
          ADPT_NEW_CR_PRINTF("rpt_carr_offset is %d\n",rpt_carr_offset);
         nim_reg_read(dev,0x102,&data,1);
         data &=0x1f;
         data |=0x20;
         nim_reg_write(dev,0x102,&data,1);
          nim_reg_read(dev,0xe5,&data,1);
          nframe = data & 0x07;
          step = (data & 0x70) >>4;
          ADPT_NEW_CR_PRINTF("nframe is %x\n",nframe);
          ADPT_NEW_CR_PRINTF("step is %x\n",step);
          nim_reg_read(dev,0x04,rdata,1);
          ADPT_NEW_CR_PRINTF("lock_st is %x\n",rdata[0]);
          //nim_reg_read(dev,0x6f,rdata,1);
          //ADPT_NEW_CR_PRINTF("fsm_st is %d\n",rdata[0]);
          */
    }
    if(priv->tsk_status.m_lock_flag == NIM_LOCK_STUS_CLEAR)
	    comm_sleep(100);
    else
	    comm_sleep(5);
	}
}

  /*****************************************************************************
* static INT32 nim_sw_snr_rpt(struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_cr_sw_snr_rpt(struct nim_device *dev)
{
	UINT8 data;
	static UINT16 snr_max = 0;
	static UINT16 snr_min = 0;
	UINT16 var;
	static INT interval_cnt = 0;

	interval_cnt++;
	if(interval_cnt==10)
	{
		nim_reg_read(dev, RBC_SNR_RPT2, &data, 1);
		if (data & 0x80) // SNR estimation data ready
		{
			var = (data & 0x1f) << 6;
			nim_reg_read(dev, RBB_SNR_RPT1, &data, 1); // read SNR LSB
			var += (data>>2) & 0x03f;

			if(snr_initial_en)
			{
				snr_max = var;
				snr_min = var;
				snr_initial_en = 0;
			}

			if(var>snr_max)
				snr_max = var;
			if(var<snr_min)
				snr_min = var;

			data = 0x00;
			nim_reg_write(dev, RBC_SNR_RPT2, &data, 1); // clear SNR ready flag

			NIM_PRINTF("*** SNR = %u min=%u max=%u\n", var, snr_min, snr_max);
		}

		interval_cnt = 0;
	}

	return SUCCESS;
}

/*****************************************************************************
* static INT32 nim_sw_adaptive_cr(struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_cr_sw_adaptive(struct nim_device *dev)
{
	UINT8 data;

	static UINT16 high_thr = 0;
	static UINT16 low_thr = 0;
	static int curr_snr_idx = 0;
	static UINT16 snr_lpf = 0;
	UINT16 var;
	INT snr_chg=0;
	INT i;
	static INT interval_cnt = 0;

	UINT16 cr_data;
	UINT8 frac,prs,irs;
	UINT32 *CR_PARA;

	//ByteDat = ReadMemB(0x180030bc);
	nim_reg_read(dev, RBC_SNR_RPT2, &data, 1);
	if (data & 0x80) // SNR estimation data ready
	{
		var = (data & 0x0f) << 6;
		//ByteDat = ReadMemB(0x180030bb);
		nim_reg_read(dev, RBB_SNR_RPT1, &data, 1); // read SNR LSB
		var += (data>>2) & 0x03f;

		// slide filter
		if(snr_initial_en)
			snr_lpf = var;
		else
		{
			snr_lpf = (snr_lpf*7+var)>>2;
			snr_lpf += 1;
			snr_lpf >>= 1;
		}
		interval_cnt++;
		if(interval_cnt==16)
		{
			interval_cnt = 0;
			//NIM_PRINTF("*** SNR = %u \r\n", snr_lpf);

		}

		if(snr_initial_en) // for first SNR data
		{
			curr_snr_idx = SNR_TAB_SIZE-1;
			for(i=SNR_TAB_SIZE-1; i>=0; i--)
			{
				if(var>=SNR_THR[i*2])
					curr_snr_idx = i;
				else
					break;
			}

			snr_initial_en = 0;
			snr_chg = 1;
			snr_lpf = var;
		}
		else if(curr_snr_idx>0 && snr_lpf>=SNR_THR[2*(curr_snr_idx-1)] && (interval_cnt==0)) // switch to lower snr
		{
			curr_snr_idx--;
			snr_chg = 1;
		}
		else if(curr_snr_idx<SNR_TAB_SIZE-1 && snr_lpf<=SNR_THR[2*curr_snr_idx+3] && (interval_cnt==0)) // to higher snr
		{
			curr_snr_idx++;
			snr_chg = 1;
		}

		if(snr_chg)
		{
			CR_PARA = (UINT32 *)CR_PARA_8PSK_3f5;
			//if((LastModCode>>2)==12) // 8PSK 3/5
			//	CR_PARA = CR_PARA_TAB[0];
			//else
			//	CR_PARA = CR_PARA_TAB[1];

			cr_data = CR_PARA[curr_snr_idx];
			frac = cr_data & 0x0f;
			prs = (cr_data>>4) & 0x0f;
			irs = (cr_data>>8) & 0x1f;
			data = (((irs & 0x03)<<4) | frac)<<2;
			//WriteMemB(0x180030bb, data);
			nim_reg_write(dev, RBB_SNR_RPT1, &data, 1);

			data = ((irs>>2)<<4) | prs | 0x80;
			//WriteMemB(0x180030bc, data);
			nim_reg_write(dev, RBC_SNR_RPT2, &data, 1);

			data = 0xe8;
			//WriteMemB(0x1800300e, 0xe8); // enable cr para update
			nim_reg_write(dev, R0E_ADPT_CR_CTRL, &data, 1);


			data = (curr_snr_idx&0x01) ? 5:0;
			NIM_PRINTF("--->switch to %d.%d dB Setting \n", 6+curr_snr_idx/2,data);
		}

		data = 0x00;
		nim_reg_write(dev, RBC_SNR_RPT2, &data, 1); // clear SNR ready flag

	}

	return SUCCESS;
}

 /*****************************************************************************

* static INT32 nim_s3503_cr_new_tab_init(struct nim_device *dev)

* NEW CR TAB initial

*

* Arguments:

*  Parameter1: struct nim_device *dev

*  Parameter2: UINT16* RsUbc

*

* Return Value: INT32

*****************************************************************************/
static INT32 nim_s3503_cr_new_tab_init(struct nim_device *dev)
{
	///	initial TAB of manson's adaptive TAB
	/*	add hy Hongyu
	*	
	*
	*	wire [2:0] TAB_ID = CR_PARA_ADDR[7:5];
	*	wire [4:0] TAB_CELL = CR_PARA_ADDR[4:0];
	*	CR_PARA_ADDR = reg_cr9d_t: this is the same as the old CR ADPT method.
	
	*	reg [29:0] S2_CODE_RATE_TABLE [27:0];
	*	reg [16:0] AWGN_COEF_TABLE [7:0];
	*	reg [18:0] LOOP_COEF_TABLE [7:0];
	*	reg [22:0] CLIP_PED_TABLE [7:0];
	*	reg [25:0] AVG_PED_TABLE [7:0];
	*	reg [29:0] S_CODE_RATE_TABLE[5:0];

	*	wire sel_S2_CODE_RATE      = (TAB_ID==0);
	*	wire sel_AWGN_COEF      = (TAB_ID==1);
	*	wire sel_LOOP_COEF      = (TAB_ID==2);
	*	wire sel_CLIP_PED       = (TAB_ID==3);
	*	wire sel_AVG_PED        = (TAB_ID==4);
	*	wire sel_S_CODE_RATE      = (TAB_ID==5);
	*
	*	S2_CODE_RATE_TABLE[TAB_CELL] <= #UDLY CR_PARA_DIN[29:0];
	*	AWGN_COEF_TABLE[TAB_CELL] <= #UDLY CR_PARA_DIN[16:0];
	*	LOOP_COEF_TABLE[TAB_CELL] <= #UDLY CR_PARA_DIN[18:0];
	*	CLIP_PED_TABLE[TAB_CELL] <= #UDLY CR_PARA_DIN[22:0];
	*	AVG_PED_TABLE[TAB_CELL] <= #UDLY CR_PARA_DIN[25:0];
	*	S_CODE_RATE_TABLE[TAB_CELL] <= #UDLY CR_PARA_DIN[29:0];
	*	
	*	CR_PARA_DIN[29:0]={
	*						reg_cr131[6:0]	// 29:23
	*						reg_cr130[7:0];	//	22:15
	*						reg_cr12_l[6:0],   //	14:8
	*						reg_cr11_l[7:0]	//	7:0
	*						}
	*	CR_PARA_WE_2 = reg_cr131[7];
	*
	*	step:	1. write CR_PARA_ADDR: TAB_ID and TAB_CELL
	*			2. write CR_PARA_DIN[14:0]: or write reg_cr11,reg_cr12, but reg_cr12[7]=0
	*			3. write reg_cr130 and reg_cr131: with reg_cr131[7]=1
	*/

	ADPT_NEW_CR_PRINTF("NEW CR TAB Initialization Begin \n");

	UINT8 TabID,CellID;
	UINT16 TabVal_14_0,TavVal_29_15;//,temp;
	UINT8 data;
	UINT8 DatArray[2];
	
	//data = 0xe1;
	//nim_reg_write(dev, R0E_ADPT_CR_CTRL,&data,1); // CR Tab init en
										// CR_TAB_INT =1

	// wire sel_CODE_RATE      = (TAB_ID==0);
	// CODE_RATE_TABLE[TAB_CELL] <= #UDLY CR_PARA_DIN[29:0];
	UINT32 S2_CODE_RATE_TABLE[28];
	UINT32 AWGN_COEF_TABLE[8];
	UINT32 LOOP_COEF_TABLE[8];
	UINT32 CLIP_PED_TABLE[8];
	UINT32 AVG_PED_TABLE[8];
	UINT32 S_CODE_RATE_TABLE[6];
	
	/*
	1) S2_CODE_RATE_TABLE size = 28*30 = 840 bits
index = {code_rate}, 28 index
value = { //30 bits
        S2_AWGN_NOISE,             //10 bits, EST_NOISE (MSBs) level to apply AWGN coefficients
        S2_AWGN_COEF_SET,  //3 bit, select one set from the AWGN_COEF table
        S2_PON_IRS_DELTA,  //3 bit signed, subtract from AWGN IRS when Pilot On
        S2_PON_PRS_DELTA,  //3 bit signed, subtract from AWGN PRS when Pilot On
        S2_LOOP_COEF_SET,  //3 bit, select one set from the CLIP_PED table
        S2_CLIP_PED_SET,   //3 bit, select one set from the CLIP_PED table
        S2_AVG_PED_SET,    //3 bit, select one set from the AVG_PED table
        S2_FORCE_OLD_CR,   //1 bit, only affect pilot off
        S2_LLR_SHIFT ,             //1 bit
        } 
	*/
	for(CellID=0; CellID<28; CellID++)
	{
//		CellID=11;
		TabID =  0;
		S2_CODE_RATE_TABLE[CellID]=((((S2_AWGN_NOISE[CellID])<<1) & 0x00000ffe)<<20) | // why?
								((S2_AWGN_COEF_SET[CellID] & 0x00000007)<<17) | 
								((S2_PON_IRS_DELTA[CellID] & 0x00000007)<<14) | 
								((S2_PON_PRS_DELTA[CellID] & 0x00000007)<<11) | 
								((S2_LOOP_COEF_SET[CellID] & 0x00000007)<<8) | 
								((S2_CLIP_PED_SET[CellID] & 0x00000007)<<5) | 
								((S2_AVG_PED_SET[CellID] & 0x00000007)<<2) | 
								((S2_FORCE_OLD_CR[CellID] & 0x00000001)<<1) | 
								(S2_LLR_SHIFT[CellID] & 0x00000001);
		//step 1: 
		data=(TabID<<5) | (CellID & 0x1f);
		nim_reg_write(dev,R9D_RPT_DEMAP_BETA,&data,1 );
		//step 2:
		TabVal_14_0 = (UINT16)((S2_CODE_RATE_TABLE[CellID]  & 0x7fff));	// and disable the CR_PARA_WE to avoid disturb with seen's adpt
		DatArray[0]=(UINT8)TabVal_14_0;
		DatArray[1]=((UINT8)(TabVal_14_0>>8)) & 0x7f;
		nim_reg_write(dev,R11_DCC_OF_I, DatArray, 2);

		//step 3:
		TavVal_29_15 = (UINT16)(S2_CODE_RATE_TABLE[CellID]>>15);
		DatArray[0]=(UINT8)(TavVal_29_15);
		DatArray[1]=(UINT8)(TavVal_29_15>>8) | 0x80;  // enable CR_PARA_WE_2
		nim_reg_write(dev,R130_CR_PARA_DIN,DatArray,2);	
	}


	/*
	2) AWGN_COEF_TABLE size = 8 * 17 = 136 bits  //AVG_PED and Wider_Loop and disabled for AWGN, SYMBOL_BEFORE_HEAD only affect pilot off
index = {AWGN_COEF_SET} 8 index
value = {
        IRS,                            //5 bits, IRS_TRA_S2 for AWGN
        IRS_FRACTION,           //2 bits
        PRS,                            //4 bits
        PRS_FRACTION,           //2 bits
        HEAD_PED_GAIN,          //3 bits
        SYMBOL_BEFORE_HEAD      //1 bit, only affect pilot off with AWGN SNR
        }

	*/
		// wire sel_AWGN_COEF      = (TAB_ID==1);
	// AWGN_COEF_TABLE[TAB_CELL] <= #UDLY CR_PARA_DIN[16:0];
	for(CellID=0; CellID<8; CellID++)
	{
		TabID =  1;
//		CellID=0;
		AWGN_COEF_TABLE[CellID]=((IRS[CellID] & 0x0000001f)<<12)  | 
								((IRS_FRACTION[CellID] & 0x00000003)<<10) | 
								((PRS[CellID] & 0x0000000f)<<6) | 
								((PRS_FRACTION[CellID] & 0x00000003)<<4) | 
								((HEAD_PED_GAIN[CellID] & 0x00000007)<<1) |
								(SYMBOL_BEFORE_HEAD[CellID] & 0x00000001);
		//step 1: 
		data=(TabID<<5) | (CellID & 0x1f);
		nim_reg_write(dev,R9D_RPT_DEMAP_BETA,&data,1 );

		//step 2:
		TabVal_14_0 = (UINT16)((AWGN_COEF_TABLE[CellID]  & 0x7fff));	// and disable the CR_PARA_WE to avoid disturb with seen's adpt
		DatArray[0]=(UINT8)TabVal_14_0;
		DatArray[1]=((UINT8)(TabVal_14_0>>8)) & 0x7f;
		nim_reg_write(dev,R11_DCC_OF_I, DatArray, 2);

		//step 3:
		TavVal_29_15 = (UINT16)(AWGN_COEF_TABLE[CellID]>>15);
		DatArray[0]=(UINT8)(TavVal_29_15);
		DatArray[1]=(UINT8)(TavVal_29_15>>8) | 0x80;  // enable CR_PARA_WE_2
		nim_reg_write(dev,R130_CR_PARA_DIN,DatArray,2);
		
	}

	/*
	3) LOOP_COEF_TABLE size = 8 * 19 = 152 bits
index = {LOOP_COEF_SET} 8 index
value = {
        HEAD_GAIN_SNR_DELTA,    //3 bits, SNR_DELTA (dB) to disable HEAD_PED_GAIN, if HEAD_PED_GAIN is big, disable it result in big bandwidth increase
        MAX_SNR_DELTA,                  //3 bits, clip SNR_DELTA so that the bandwidth doesn't become too big for high SNR_DELTA
        IRS_STEP,                               //3 bits, IRS step for each SNR_DELTA, have 2 bits fraction (same as IRS_FRACTION)
        PRS_STEP,                               //3 bits
        WIDER_SNR_DELTA,                //3 bits, SNR_DELTA to enable WIDER_LOOP, =7 means WIDER_LOOP always disabled
        WIDER_IRS_DELTA,                //2 bits
        WIDER_PRS_DELTA                 //2 bits
        }
	*/
	// wire sel_LOOP_COEF      = (TAB_ID==2);
	// LOOP_COEF_TABLE[TAB_CELL] <= #UDLY CR_PARA_DIN[18:0];
	for(CellID=0; CellID<8; CellID++)
	{
//		CellID=0;
		TabID =  2;
		LOOP_COEF_TABLE[CellID]=((HEAD_GAIN_SNR_DELTA[CellID] & 0x00000007)<<16) |
								((MAX_SNR_DELTA[CellID] & 0x00000007)<<13) | 
							    ((IRS_STEP[CellID] & 0x00000007)<<10) | 
								((PRS_STEP[CellID] & 0x00000007)<<7) | 
								((WIDER_SNR_DELTA[CellID] & 0x00000007)<<4) | 
								((WIDER_IRS_DELTA[CellID] & 0x00000003)<<2) | 
								(WIDER_PRS_DELTA[CellID] & 0x00000003);
		//step 1: 
		data=(TabID<<5) | (CellID & 0x1f);
		nim_reg_write(dev,R9D_RPT_DEMAP_BETA,&data,1 );

		//step 2:
		TabVal_14_0 = (UINT16)((LOOP_COEF_TABLE[CellID]  & 0x7fff));	// and disable the CR_PARA_WE to avoid disturb with seen's adpt
		DatArray[0]=(UINT8)TabVal_14_0;
		DatArray[1]=((UINT8)(TabVal_14_0>>8)) & 0x7f;
		nim_reg_write(dev,R11_DCC_OF_I, DatArray, 2);

		//step 3:
		TavVal_29_15 = (UINT16)(LOOP_COEF_TABLE[CellID]>>15);
		DatArray[0]=(UINT8)(TavVal_29_15);
		DatArray[1]=(UINT8)(TavVal_29_15>>8) | 0x80;  // enable CR_PARA_WE_2
		nim_reg_write(dev,R130_CR_PARA_DIN,DatArray,2);
	}

	/*
	4) CLIP_PED_TABLE, size = 8*23 = 184 bits
index = {CLIP_PED_SET}, 8 index
value = {
        CLIP_MULT_STEP, //5 bits, step to increase CLIP_PED1 and 2 if SNR_DELTA > 0
        CLIP_PED1_EN,   //1 bit
        CLIP_PED1,              //8 bits
        CLIP_PED2_EN,   //1 bit
        CLIP_PED2               //8 bits
        }

	*/
		// wire sel_CLIP_PED       = (TAB_ID==3);
	// CLIP_PED_TABLE[TAB_CELL] <= #UDLY CR_PARA_DIN[22:0];
	for(CellID=0; CellID<8; CellID++)
	{
//		CellID=0;
		TabID =  3;
		CLIP_PED_TABLE[CellID]=((CLIP_MULT_STEP[CellID] & 0x0000001f)<<18) | 
								((CLIP_PED1_EN[CellID]  & 0x00000001)<< 17) | 
								((CLIP_PED1[CellID] & 0x000000ff)<<9) | 
								((CLIP_PED2_EN[CellID] & 0x00000001)<<8)	|
								(CLIP_PED2[CellID] & 0x000000ff);
		//step 1: 
		data=(TabID<<5) | (CellID & 0x1f);
		nim_reg_write(dev,R9D_RPT_DEMAP_BETA,&data,1 );

		//step 2:
		TabVal_14_0 = (UINT16)((CLIP_PED_TABLE[CellID]  & 0x7fff));	// and disable the CR_PARA_WE to avoid disturb with seen's adpt
		DatArray[0]=(UINT8)TabVal_14_0;
		DatArray[1]=((UINT8)(TabVal_14_0>>8)) & 0x7f;
		nim_reg_write(dev,R11_DCC_OF_I, DatArray, 2);

		//step 3:
		TavVal_29_15 = (UINT16)(CLIP_PED_TABLE[CellID]>>15);
		DatArray[0]=(UINT8)(TavVal_29_15);
		DatArray[1]=(UINT8)(TavVal_29_15>>8) | 0x80;  // enable CR_PARA_WE_2
		nim_reg_write(dev,R130_CR_PARA_DIN,DatArray,2);
	}



		// wire sel_AVG_PED        = (TAB_ID==4);
	// AVG_PED_TABLE[TAB_CELL] <= #UDLY CR_PARA_DIN[25:0];
/*	5) AVG_PED_TABLE, size = 8*26 = 224 bits
	index = {code_rate}, 8 index
	value = {
        AVG_SNR_DELTA,  //3 bits SNR_DELTA to apply AVG_PED
        AVG_MULT_STEP,  //5 bits, step to increase AVG_PED1 and 2 if SNR_DELTA > AVG_SNR_DELTA
        AVG_PED1_EN,    //1 bit 
        AVG_PED1,               //8 bits
        AVG_PED2_en,    //1 bit
        AVG_PED2,               //8 bits
        }
*/
	for(CellID=0; CellID<8; CellID++)
	{
//		CellID=0;
		TabID =  4;
		AVG_PED_TABLE[CellID]=((AVG_SNR_DELTA[CellID] & 0x00000007)<<23) | 
								((AVG_MULT_STEP[CellID] & 0x0000001f)<<18) | 
								((AVG_PED1_EN[CellID] & 0x00000001)<<17) | 
								((AVG_PED1[CellID] & 0x000000ff)<<9) | 
								((AVG_PED2_en[CellID] & 0x00000001)<<8)	|
								(AVG_PED2[CellID] & 0x000000ff);
		//step 1: 
		data=(TabID<<5) | (CellID & 0x1f);
		nim_reg_write(dev,R9D_RPT_DEMAP_BETA,&data,1 );

		//step 2:
		TabVal_14_0 = (UINT16)((AVG_PED_TABLE[CellID]  & 0x7fff));	// and disable the CR_PARA_WE to avoid disturb with seen's adpt
		DatArray[0]=(UINT8)TabVal_14_0;
		DatArray[1]=((UINT8)(TabVal_14_0>>8)) & 0x7f;
		nim_reg_write(dev,R11_DCC_OF_I, DatArray, 2);

		//step 3:
		TavVal_29_15 = (UINT16)(AVG_PED_TABLE[CellID]>>15);
		DatArray[0]=(UINT8)(TavVal_29_15);
		DatArray[1]=(UINT8)(TavVal_29_15>>8) | 0x80;  // enable CR_PARA_WE_2
		nim_reg_write(dev,R130_CR_PARA_DIN,DatArray,2);
	}

	/*
	6) S_CODE_RATE_TABLE size = 28*30 = 840 bits
	index = {code_rate}, 28 index
	value = { //30 bits
        S_AWGN_NOISE,             //10 bits, EST_NOISE (MSBs) level to apply AWGN coefficients
        S_AWGN_COEF_SET,  //3 bit, select one set from the AWGN_COEF table
        S_PON_IRS_DELTA,  //3 bit signed, subtract from AWGN IRS when Pilot On
        S_PON_PRS_DELTA,  //3 bit signed, subtract from AWGN PRS when Pilot On
        S_LOOP_COEF_SET,  //3 bit, select one set from the CLIP_PED table
        S_CLIP_PED_SET,   //3 bit, select one set from the CLIP_PED table
        S_AVG_PED_SET,    //3 bit, select one set from the AVG_PED table
        S_FORCE_OLD_CR,   //1 bit, only affect pilot off
        S_LLR_SHIFT ,             //1 bit
        } 
	*/
	for(CellID=0; CellID<6; CellID++)
	{
//		CellID=11;
		TabID =  5;
		S_CODE_RATE_TABLE[CellID]=((((S_AWGN_NOISE[CellID])<<1) & 0x00000ffe)<<20) | // why?
								((S_AWGN_COEF_SET[CellID] & 0x00000007)<<17) | 
								((S_PON_IRS_DELTA[CellID] & 0x00000007)<<14) | 
								((S_PON_PRS_DELTA[CellID] & 0x00000007)<<11) | 
								((S_LOOP_COEF_SET[CellID] & 0x00000007)<<8) | 
								((S_CLIP_PED_SET[CellID] & 0x00000007)<<5) | 
								((S_AVG_PED_SET[CellID] & 0x00000007)<<2) | 
								((S_FORCE_OLD_CR[CellID] & 0x00000001)<<1) | 
								(S_LLR_SHIFT[CellID] & 0x00000001);
		//step 1: 
		data=(TabID<<5) | (CellID & 0x1f);
		nim_reg_write(dev,R9D_RPT_DEMAP_BETA,&data,1 );

		//step 2:
		TabVal_14_0 = (UINT16)((S_CODE_RATE_TABLE[CellID]  & 0x7fff));	// and disable the CR_PARA_WE to avoid disturb with seen's adpt
		DatArray[0]=(UINT8)TabVal_14_0;
		DatArray[1]=((UINT8)(TabVal_14_0>>8)) & 0x7f;
		nim_reg_write(dev,R11_DCC_OF_I, DatArray, 2);

		//step 3:
		TavVal_29_15 = (UINT16)(S_CODE_RATE_TABLE[CellID]>>15);
		DatArray[0]=(UINT8)(TavVal_29_15);
		DatArray[1]=(UINT8)(TavVal_29_15>>8) | 0x80;  // enable CR_PARA_WE_2
		nim_reg_write(dev,R130_CR_PARA_DIN,DatArray,2);	
	}
	
	// setting SNR_EST_LEN to 7, so that the value of EST_NOISE can keep stable.
	nim_reg_read(dev,R113_NEW_CR_ADPT_CTRL,&data,1);
	data |=0x70;
	nim_reg_write(dev,R113_NEW_CR_ADPT_CTRL,&data,1);

	ADPT_NEW_CR_PRINTF("NEW CR TAB Initialization Done \n");

	return SUCCESS;
}
static INT32 nim_s3503_NframeStepTso_setting(struct nim_device *dev,UINT32 *sym_rate,UINT8 s_Case)
{
    UINT8 rdata[2];
    static UINT8 last_lock_st = 0x00;
    UINT8 current_lock_st=0x00;
   
    nim_reg_read(dev,R04_STATUS,&current_lock_st,1);
    current_lock_st &=0x3f;
    
    if(((current_lock_st != 0x3f) && (s_Case==0x00)) | (s_Case==0x01))
    {   // s_Case==0x00 called by task function
        // s_Case==0x01 called by channnel change function
            nim_reg_read(dev,R124_HEAD_DIFF_NFRAME,rdata,2);
            rdata[0] &= 0x88;
            rdata[0] |= 0x21;
            rdata[1] &= 0x88;
            rdata[1] |= 0x32;
            nim_reg_write(dev,R124_HEAD_DIFF_NFRAME,rdata,2);
            nim_reg_read(dev,R124_HEAD_DIFF_NFRAME,rdata,2);
            ADPT_NEW_CR_PRINTF("channel change:\n\tnframe is %x\n\tstep is %x\nTSO is OFF\n",rdata[0],rdata[1]);
            nim_s3503_tso_off(dev);
    }
    if((last_lock_st != 0x3f) && (current_lock_st==0x3f))
     {
                nim_reg_read(dev,R124_HEAD_DIFF_NFRAME,rdata,2);
                //ADPT_NEW_CR_PRINTF("all state lock and change nframe/step:\n\tnframe is %x\n\tstep is %x\n",rdata[0],rdata[1]);
                rdata[0] &= 0x88;
                rdata[0] |= 0x74;
                rdata[1] &= 0x88;
                rdata[1] |= 0x70;
                nim_reg_write(dev,R124_HEAD_DIFF_NFRAME,rdata,2);
                nim_reg_read(dev,R124_HEAD_DIFF_NFRAME,rdata,2);
                ADPT_NEW_CR_PRINTF("normal mode:\n\tnframe is %x\n\tstep is %x\nTSO is ON\n",rdata[0],rdata[1]);
                nim_s3503_tso_on(dev);
                }
     last_lock_st=current_lock_st;

  
    return SUCCESS;
}
static INT32 nim_s3503_cr_new_modcod_table_init(struct nim_device *dev,UINT32 sym)
{
    /*
        To Re-initial S2_CODE_RATE_table according to symbol rate
    */
   ADPT_NEW_CR_PRINTF("Re-inital S2_CODE_RATE_table Begin\n");

    UINT8 TabID,CellID;
	UINT16 TabVal_14_0,TavVal_29_15;//,temp;
	UINT8 data;
	UINT8 DatArray[2];
    UINT32 AWGN_COEF_TABLE[8];
    
    UINT16 S2_AWGN_NOISE_tmp;
    UINT8 S2_AWGN_COEF_SET_tmp;
    UINT8 S2_PON_IRS_DELTA_tmp;
    UINT8 S2_PON_PRS_DELTA_tmp;
    UINT8 S2_LOOP_COEF_SET_tmp;
    UINT8 S2_CLIP_PED_SET_tmp;
    UINT8 S2_AVG_PED_SET_tmp;
    UINT8 S2_FORCE_OLD_CR_tmp;
    
    UINT8 IRS_tmp;
    UINT8 IRS_FRACTION_tmp;
    UINT8 PRS_tmp;
    UINT8 PRS_FRACTION_tmp;
    UINT8 HEAD_PED_GAIN_tmp;
    UINT8 SYMBOL_BEFORE_HEAD_tmp;

	UINT32 S2_CODE_RATE_TABLE[28];

     for(CellID=0; CellID<28; CellID++)
	    {
            TabID =  0;
            if((6500<sym) && (sym<33000))
            {
                S2_AWGN_NOISE_tmp=S2_AWGN_NOISE_EXTRA[CellID];
                S2_PON_IRS_DELTA_tmp=S2_PON_IRS_DELTA_EXTRA[CellID];
                S2_PON_PRS_DELTA_tmp=S2_PON_PRS_DELTA_EXTRA[CellID];
                S2_CLIP_PED_SET_tmp=S2_CLIP_PED_SET_EXTRA[CellID];
                S2_AVG_PED_SET_tmp=S2_AVG_PED_SET_EXTRA[CellID];
                S2_AWGN_COEF_SET_tmp=S2_AWGN_COEF_SET_EXTRA[CellID];
                S2_LOOP_COEF_SET_tmp=S2_LOOP_COEF_SET_EXTRA[CellID];
                S2_FORCE_OLD_CR_tmp=S2_FORCE_OLD_CR[CellID];
                if((CellID==13) && (sym<16000)) // patch for 8psk R3_4 using 5M parameters
                {
                      S2_LOOP_COEF_SET_tmp=0x0;// LOOP_COEF_table dont EXTRA
                      S2_AWGN_COEF_SET_tmp=0x7;
                      S2_FORCE_OLD_CR_tmp=0x1;
                }
                if((CellID==11) && (sym<16000)) //pathc for 8psk R3_5
                {
                      S2_AWGN_COEF_SET_tmp=0x6;//
                      S2_AVG_PED_SET_tmp=0x6;
                      S2_FORCE_OLD_CR_tmp=0x1;
                      S2_PON_PRS_DELTA_tmp=0;
                      S2_PON_IRS_DELTA_tmp=0;
                }
                if((CellID==12) && (sym<16000))// patch for 8psk R2_3
                {
                       S2_AWGN_COEF_SET_tmp=0x6;
                       //S2_AWGN_NOISE_tmp=0x8c;//0xa0
                       S2_LOOP_COEF_SET_tmp=0x5;
                       S2_FORCE_OLD_CR_tmp=0x1;
                }
                if((CellID==14) && (sym<16000))// for 8psk R5_6
                {
                    S2_AWGN_COEF_SET_tmp=0x7;
                    S2_LOOP_COEF_SET_tmp=0x6;
                }
                if((CellID==3) && (sym<12000))// for qpsk R1_2
                {
                  // S2_FORCE_OLD_CR_tmp=0x1;
                  S2_AWGN_COEF_SET_tmp=0x1;
                  S2_PON_PRS_DELTA_tmp=0x7;// in order to not infulence pilot on
                  S2_PON_IRS_DELTA_tmp=0x7;
                  S2_AWGN_NOISE_tmp = 0x1c9;// only for 6.5M to 16M
                }
            }
            else
            {
                S2_AWGN_NOISE_tmp=S2_AWGN_NOISE[CellID];
                S2_AWGN_COEF_SET_tmp=S2_AWGN_COEF_SET[CellID];
                S2_LOOP_COEF_SET_tmp=S2_LOOP_COEF_SET[CellID];
                S2_CLIP_PED_SET_tmp=S2_CLIP_PED_SET[CellID];
                S2_AVG_PED_SET_tmp=S2_AVG_PED_SET[CellID];
                S2_PON_IRS_DELTA_tmp=S2_PON_IRS_DELTA[CellID];
                S2_PON_PRS_DELTA_tmp=S2_PON_PRS_DELTA[CellID];
                S2_FORCE_OLD_CR_tmp=S2_FORCE_OLD_CR[CellID];
                if((CellID==11) && (sym<4000))// patch for 8psk R3_5 symbol_rate<4000
                {
                    S2_PON_IRS_DELTA_tmp=0x6;
                    S2_PON_PRS_DELTA_tmp=0x6;
                    ADPT_NEW_CR_PRINTF("below 4000\n");
                } 
                if((CellID==3) && (sym<=6500))// for qpsk R1_2
                {
					S2_AWGN_NOISE_tmp = 0x1ed;
                    S2_AWGN_COEF_SET_tmp=0x1;
                }   
            }
		    if(CellID==11)ADPT_NEW_CR_PRINTF("S2_PON_IRS_DELTA_tmp is %d\n",S2_PON_IRS_DELTA_tmp);
		    S2_CODE_RATE_TABLE[CellID]=((((S2_AWGN_NOISE_tmp)<<1) & 0x00000ffe)<<20) | // why?
								((S2_AWGN_COEF_SET_tmp & 0x00000007)<<17) | 
								((S2_PON_IRS_DELTA_tmp & 0x00000007)<<14) | 
								((S2_PON_PRS_DELTA_tmp & 0x00000007)<<11) | 
								((S2_LOOP_COEF_SET_tmp & 0x00000007)<<8) | 
								((S2_CLIP_PED_SET_tmp & 0x00000007)<<5) | 
								((S2_AVG_PED_SET_tmp & 0x00000007)<<2) | 
								((S2_FORCE_OLD_CR_tmp & 0x00000001)<<1) | 
								(S2_LLR_SHIFT[CellID] & 0x00000001);
		    //step 1: 
		    data=(TabID<<5) | (CellID & 0x1f);
		    nim_reg_write(dev,R9D_RPT_DEMAP_BETA,&data,1 );
		    //step 2:
		    TabVal_14_0 = (UINT16)((S2_CODE_RATE_TABLE[CellID]  & 0x7fff));	// and disable the CR_PARA_WE to avoid disturb with seen's adpt
		    DatArray[0]=(UINT8)TabVal_14_0;
		    DatArray[1]=((UINT8)(TabVal_14_0>>8)) & 0x7f;
		    nim_reg_write(dev,R11_DCC_OF_I, DatArray, 2);

		    //step 3:
		    TavVal_29_15 = (UINT16)(S2_CODE_RATE_TABLE[CellID]>>15);
		    DatArray[0]=(UINT8)(TavVal_29_15);
		    DatArray[1]=(UINT8)(TavVal_29_15>>8) | 0x80;  // enable CR_PARA_WE_2
		    nim_reg_write(dev,R130_CR_PARA_DIN,DatArray,2);	
	    }

	for(CellID=0; CellID<8; CellID++)
	{
		TabID =  1;
        if((6500<sym) && (sym<33000))
        {
            
                IRS_tmp=IRS_EXTRA[CellID];
                IRS_FRACTION_tmp=IRS_FRACTION_EXTRA[CellID];
                PRS_tmp=PRS_EXTRA[CellID];
                PRS_FRACTION_tmp=PRS_FRACTION_EXTRA[CellID];
                HEAD_PED_GAIN_tmp=HEAD_PED_GAIN_EXTRA[CellID];
                SYMBOL_BEFORE_HEAD_tmp=SYMBOL_BEFORE_HEAD_EXTRA[CellID];
                ADPT_NEW_CR_PRINTF("6500<sym<33000\n");
        }
        else
        {
            IRS_tmp=IRS[CellID];
            IRS_FRACTION_tmp=IRS_FRACTION[CellID];
            PRS_tmp=PRS[CellID];
            PRS_FRACTION_tmp=PRS_FRACTION[CellID];
            HEAD_PED_GAIN_tmp=HEAD_PED_GAIN[CellID];
            SYMBOL_BEFORE_HEAD_tmp=SYMBOL_BEFORE_HEAD[CellID];
            ADPT_NEW_CR_PRINTF("sym<6500 or sym>33000\n");
        }
		AWGN_COEF_TABLE[CellID]=((IRS_tmp & 0x0000001f)<<12)  | 
								((IRS_FRACTION_tmp & 0x00000003)<<10) | 
								((PRS_tmp & 0x0000000f)<<6) | 
								((PRS_FRACTION_tmp & 0x00000003)<<4) | 
								((HEAD_PED_GAIN_tmp & 0x00000007)<<1) |
								(SYMBOL_BEFORE_HEAD_tmp & 0x00000001);
		//step 1: 
		data=(TabID<<5) | (CellID & 0x1f);
		nim_reg_write(dev,R9D_RPT_DEMAP_BETA,&data,1 );

		//step 2:
		TabVal_14_0 = (UINT16)((AWGN_COEF_TABLE[CellID]  & 0x7fff));	// and disable the CR_PARA_WE to avoid disturb with seen's adpt
		DatArray[0]=(UINT8)TabVal_14_0;
		DatArray[1]=((UINT8)(TabVal_14_0>>8)) & 0x7f;
		nim_reg_write(dev,R11_DCC_OF_I, DatArray, 2);

		//step 3:
		TavVal_29_15 = (UINT16)(AWGN_COEF_TABLE[CellID]>>15);
		DatArray[0]=(UINT8)(TavVal_29_15);
		DatArray[1]=(UINT8)(TavVal_29_15>>8) | 0x80;  // enable CR_PARA_WE_2
		nim_reg_write(dev,R130_CR_PARA_DIN,DatArray,2);
		
	}
 
    ADPT_NEW_CR_PRINTF("Re-inital S2_CODE_RATE_table Done\n");
    return SUCCESS;
 }

  static INT32 nim_s3503_cr_new_adaptive_unlock_monitor(struct nim_device *dev)
  {// this function is to lock when strong noise
     UINT8 rdata[2],data;
     UINT16 est_noise ; // here must be test again
     UINT16 rdata16;
     UINT8 fec_lock_st=0x00;
     static UINT8 last_fec_lock_st=0x00;
     UINT8 cr_adpt_choice;
     UINT8 cr_para_en;
     static UINT8 cr_para_en_flag=0;
     nim_reg_read(dev,R13b_EST_NOISE,rdata,2);
     rdata16 = rdata[1];
     est_noise = (rdata[0] | (rdata16 << 8)) >> 4; // here must be test again
  
     nim_reg_read(dev,R04_STATUS,&fec_lock_st,1);
     fec_lock_st &=0x3f;// complicable with DVBS
      
     nim_reg_read(dev,0x13a,&cr_adpt_choice,1);
     cr_adpt_choice = cr_adpt_choice >>4;
     cr_adpt_choice &= 0x03;// when using OldAdpt, dont need to change coefficients
    nim_reg_read(dev,0x113,&cr_para_en,1);
    cr_para_en &=0x02;// Only for new adpt
     
     if((est_noise == 0x1ff) && (fec_lock_st != 0x3f) && (cr_adpt_choice != 0x02) && ((cr_para_en == 0x02) | cr_para_en_flag))
     {
        // add by hongyu for CR LOCK Based on NEW ADPT Begin
         nim_reg_read(dev,RB5_CR_PRS_TRA,&data,1);//prs
         data &=0x0f;
         data |=0x70;
         nim_reg_write(dev,RB5_CR_PRS_TRA,&data,1);
         nim_reg_read(dev,0x37,&data,1);//irs
         data &=0x83;
         data |= 0x48;
         nim_reg_write(dev,0x37,&data,1);
         nim_reg_read(dev,RE0_PPLL_CTRL,&data,1);//sbh
         data |= 0x20;// enable symbol before head
         data &= 0xf7;// disable force_old_cr
         nim_reg_write(dev,RE0_PPLL_CTRL,&data,1);
         nim_reg_read(dev,0x127,&data,1);//hpg
         data &= 0x8f;
         nim_reg_write(dev,0x127,&data,1);
         nim_reg_read(dev,0x137,&data,1);//clip_ped
         data &= 0xee;
         nim_reg_write(dev,0x137,&data,1);
          // add by hongyu for CR LOCK Based on NEW ADPT end
     
     //data = 0x20;                    
     //nim_reg_write(dev,0x13a,&data,1);
     
     nim_reg_read(dev,0x113,&data,1);
     data &=0xfd;
     nim_reg_write(dev,0x113,&data,1);
     cr_para_en_flag=1;
     //comm_sleep(1000); // waiting for CR LOCK 
     
     
     ADPT_NEW_CR_PRINTF("strong phase noise happened and try register parameters\n");
     }
    // ADPT_NEW_CR_PRINTF("last_fec_lock_st is %x\nfec_lock_st is %x\ncr_adpt_choice is %x\ncr_para_en_flag is %x\n ");
    if((last_fec_lock_st != 0x3f) && (fec_lock_st == 0x3f)  && cr_para_en_flag)
    {
         nim_reg_read(dev,0x113,&data,1);
         data |=0x02;
         nim_reg_write(dev,0x113,&data,1); 
         ADPT_NEW_CR_PRINTF("change to NEW ADPT\n");
         cr_para_en_flag=0;
    }
    last_fec_lock_st = fec_lock_st;
     return  SUCCESS;
  }

  /*****************************************************************************
* static INT32 nim_s3503_cr_tab_init(struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_cr_tab_init(struct nim_device *dev)
{
	UINT8 TabID,CellID;
	UINT32 TabVal, TabValTemp;
	UINT8 data;
	UINT8 DatArray[2];
/*  TAB_ID=15, CellID = 0,1,2,3
bits         14 13 12 11   10     9       8       7        6    5        4    3       2     1        0
OLD_CR |         Reserved     |  32APSK   |  16APSK  |  8PSK   | S2_QPSK |        |
                                 PON  POF   PON  POF  PON POF   PON POFF  DVBS
   0x01                          0     0     0    0   0   1      0  0       1
WIDE_1 |      Reserved   |     32     |   16   |<------16APSK POFF------>|        |
                            PON POF    PON   9/10  8/9  5/6  4/5  3/4  2/3 8_PON
   0x81                     0    0      0     0     0   0     0    0    0     0 
WIDE_2 |   Reserved                 |<------8PSK POFF-------->|  S2_QPSK |        |		
                                  9/10  8/9  5/6  3/4  2/3  3/5   PON POFF   DVBS
   0x006                          0     0    0    0    0     0     0    1       0
SNR_EN       |   32   | 16APSK |     |<------8PSK POFF---------->|  S2_QPSK |     |
              ON POF    PON POF 8ON 9/10  8/9  5/6  3/4  2/3  3/5   PON  POFF  DVBS
  0x5f8       0   0     0   1    0   1    1    1    1    1     1     0    1     0  
*/
                                // OLD_CR  WIDE_1  WIDE_2  SNR_EN  CR_FIX  HEAD
	//const unsigned OTHERS_TAB[6] = {0x09,    0x00,    0x002,   0x5fa,    0x000,   0x00};
	const unsigned OTHERS_TAB[6] = {0x09,    0x00,    0x002,   0x5fa,    0x000,   0x00};
   // const unsigned OTHERS_TAB[6] = {0x00,    0x00,    0x002,   0x5fa,    0x000,   0x00};

	#ifdef HW_ADPT_CR_MONITOR
		ADPT_CR_PRINTF("CR TAB Initialization Begin \n");
	#endif
	data = 0xe1; // CR Tab init en
	nim_reg_write(dev, R0E_ADPT_CR_CTRL, &data, 1);

	// Write SNR threshold low, TabID=0~1;
	for(CellID=0; CellID<SNR_TAB_SIZE; CellID++)
	{
		TabID =  (CellID>=16) ? 1 : 0;
		data = (TabID<<4) | (CellID & 0x0f);
		nim_reg_write(dev, R9D_RPT_DEMAP_BETA, &data, 1);
		TabVal = SNR_THR[2*CellID]  | 0x8000;
		DatArray[0] = (UINT8)(TabVal & 0x0ff);
		DatArray[1] = (UINT8)((TabVal>>8) & 0x0ff);
		nim_reg_write(dev, R11_DCC_OF_I, DatArray, 2);
	}

      // Write SNR threshold high, TabID=2~3;
	for(CellID=0; CellID<SNR_TAB_SIZE; CellID++)
	{

		TabID =  (CellID>=16) ? 3 : 2;
		data = (TabID<<4) | (CellID & 0x0f);
		nim_reg_write(dev, R9D_RPT_DEMAP_BETA, &data, 1);
		TabVal = SNR_THR[2*CellID+1] | 0x8000;
		DatArray[0] = (UINT8)(TabVal & 0x0ff);
		DatArray[1] = (UINT8)((TabVal>>8) & 0x0ff);
		nim_reg_write(dev, R11_DCC_OF_I, DatArray, 2);
	}

	// Write CR PRS/IRS/FRAC/HEAD_GAIN
	// SW format: {IRS[4:0],  PRS[3:0], HEAD_GAIN[3:0], FRAC[3:0],}
	// HW format: {HEAD_GAIN[2:0],FRAC[1:0],IRS[4:0], PRS[3:0]}
        // 8PSK 3/5, TabID=4;
	for(CellID=0; CellID<PSK8_TAB_SIZE; CellID++)
	{
		data = (4<<4) | CellID;
		nim_reg_write(dev, R9D_RPT_DEMAP_BETA, &data, 1);
		TabVal = CR_PARA_8PSK_3f5[CellID];
		TabValTemp = (TabVal & 0x7c)<<7;
		TabVal = (TabVal>>8) | TabValTemp | 0x8000;  // to HW format;
		DatArray[0] = (UINT8)(TabVal & 0x0ff);
		DatArray[1] = (UINT8)((TabVal>>8) & 0x0ff);
		nim_reg_write(dev, R11_DCC_OF_I, DatArray, 2);
	}

	// 8PSK 2/3 ~ 9/10,  3/4~9/10 share one group
	for(TabID=5; TabID<=6; TabID++)
	{	
		for(CellID=0; CellID<PSK8_TAB_SIZE; CellID++)
		{
			data = (TabID<<4) | CellID;
			nim_reg_write(dev, R9D_RPT_DEMAP_BETA, &data, 1);
			TabVal = CR_PARA_8PSK_others[CellID];
			TabValTemp = (TabVal & 0x7c)<<7;
			TabVal = (TabVal>>8) |TabValTemp | 0x8000;  // to HW format;
			DatArray[0] = (UINT8)(TabVal & 0x0ff);
			DatArray[1] = (UINT8)((TabVal>>8) & 0x0ff);
			nim_reg_write(dev, R11_DCC_OF_I, DatArray, 2);
		}
	}

	// QPSK: TabID=7~9, need parameter table later
	for(TabID=7; TabID<=9; TabID++)
	{	
		for(CellID=0; CellID<QPSK_TAB_SIZE; CellID++)
		{
			data = (TabID<<4) | CellID;
			nim_reg_write(dev, R9D_RPT_DEMAP_BETA, &data, 1);
			TabVal = 0x129 | 0x8000;
			DatArray[0] = (UINT8)(TabVal & 0x0ff);
			DatArray[1] = (UINT8)((TabVal>>8) & 0x0ff);
			nim_reg_write(dev, R11_DCC_OF_I, DatArray, 2);
		}
	}

	// 16APSK: TabID=10~12
	for(TabID=10; TabID<=12; TabID++)
	{	
		for(CellID=0; CellID<APSK16_TAB_SIZE; CellID++)
		{
			data = (TabID<<4) | CellID;
			nim_reg_write(dev, R9D_RPT_DEMAP_BETA, &data, 1);
			TabVal = 0x129 | 0x8000;
			DatArray[0] = (UINT8)(TabVal & 0x0ff);
			DatArray[1] = (UINT8)((TabVal>>8) & 0x0ff);
			nim_reg_write(dev, R11_DCC_OF_I, DatArray, 2);	
		}
	}
	
	        // ON/OFF Table
	 for(CellID=0; CellID<6; CellID++)
	{
		data = 0xf0 | CellID;
		nim_reg_write(dev, R9D_RPT_DEMAP_BETA, &data, 1);
		TabVal = OTHERS_TAB[CellID] | 0x8000;
		DatArray[0] = (UINT8)(TabVal & 0x0ff);
		DatArray[1] = (UINT8)((TabVal>>8) & 0x0ff);
		nim_reg_write(dev, R11_DCC_OF_I, DatArray, 2);
	}		
	
	data = 0xe0; // CR Tab init off
	nim_reg_write(dev, R0E_ADPT_CR_CTRL, &data, 1);

	#ifdef HW_ADPT_CR_MONITOR
		ADPT_CR_PRINTF("CR TAB Initialization Done \n");
	#endif
	return SUCCESS;
}

static INT32 nim_s3503_set_32apsk_target(struct nim_device *dev)
{
/******************************************************************************
* fuction describle:
*	this fuction is used to initial the value of the S2_32APSK_TARGET
*	because of test results show that perfomance of c3503 fpga is better when disabled then enabled, 
*	this function dont need to be called. 
*
*
*	          	 FORCE_OLD_DEMAP_AGC3 = reg_cre0[6];		init:	0
*               	 DIRECT_POWER_EN= reg_creb[3],			init:	1
*
*                 	 S2_Q8PSK_SKIP_DATA,
*                  	 S2_16APSK_SKIP_DATA_PON=reg_creb[1],	init:	0
*                 	 S2_16APSK_SKIP_DATA_POFF= reg_creb[2],	init:	0
*                  	 S2_32APSK_SKIP_DATA_PON= reg_cre9[4],	init:	0
*                    S2_32APSK_SKIP_DATA_POFF= reg_cre9[5], 	init:	0
*          [6:0]   S2_16APSK_TARGET= reg_crec[6:0],		init:	0x1d
*          [6:0]   S2_32APSK_TARGET=reg_crea[6:0],		init:	0x1d
*          [6:0]   S_TARGET= reg_cre7[6:0],				init:	0x30
*          [6:0]   S2_TARGET= reg_cre8[6:0],			init:	0x29
******************************************************************************/
	UINT8 rdata;

	//FORCE_OLD_DEMAP_AGC3
	nim_reg_read(dev,0xe0, &rdata,1);
	rdata &= 0xbf;
	nim_reg_write(dev,0xe0, &rdata,1);

	// DIRECT_POWER_EN S2_16APSK_SKIP_DATA_PON S2_16APSK_SKIP_DATA_POFF
	nim_reg_read(dev,0xeb,&rdata,1);
	rdata &=0xf6;
	rdata |=0x08;
	nim_reg_write(dev,0xeb,&rdata,1);

	//S2_32APSK_SKIP_DATA_PON  S2_32APSK_SKIP_DATA_POFF
	nim_reg_read(dev,0xe9,&rdata,1);
	rdata &=0xcf;
	nim_reg_write(dev,0xe9,&rdata,1);

	//S2_16APSK_TARGET
	nim_reg_read(dev,0xec,&rdata,1);
	rdata |=0x1d;
	nim_reg_write(dev,0xec,&rdata,1);

	//S2_32APSK_TARGET
	nim_reg_read(dev,0xea,&rdata,1);
	rdata |=0x1d;
	nim_reg_write(dev,0xea,&rdata,1);

	// S_TARGET
	nim_reg_read(dev,0xe7,&rdata,1);
	rdata |=0x30;
	nim_reg_write(dev,0xe7,&rdata,1);

	// S2_TARGET
	nim_reg_read(dev,0xe8,&rdata,1);
	rdata |=0x29;
	nim_reg_write(dev,0xe8,&rdata,1);

}

/******************************************************************************
   * 
static INT32 nim_s3503_fec_llr_shift(struct nim_device *dev)
*   function describle: 
*	if this fuction is execute, it will detect reg_cr113[0]. if reg_cr113[0] equal to one, it will re-initial
*	NEW CR parameter TAB about LLR_SHIFT to one.
*	if reg_cr113[0] equal to zero, it will re-initial NEW CR parameter TAB about LLR_SHIFT to zero
*
******************************************************************************/
static INT32 nim_s3503_fec_llr_shift(struct nim_device *dev)
{
	UINT32 S2_CODE_RATE_TABLE[28];
	UINT32 S_CODE_RATE_TABLE[6];
	UINT8 CellID,TabID;
	UINT8 data;
	UINT8 DatArray[2];
	UINT16 TabVal_14_0,TavVal_29_15;
	UINT8 reg_llr_shift;
	
	UINT8 rdata;
	static UINT8 last_value;
	nim_reg_read(dev,0x113,&rdata,1);
	rdata &= 0x01;
	if(last_value!=rdata)
	{
		last_value = rdata;
	if(rdata==0x01) // enable LLR_SHIFT
	{
	/*
	1) S2_CODE_RATE_TABLE size = 28*30 = 840 bits
index = {code_rate}, 28 index
value = { //30 bits
        S2_AWGN_NOISE,             //10 bits, EST_NOISE (MSBs) level to apply AWGN coefficients
        S2_AWGN_COEF_SET,  //3 bit, select one set from the AWGN_COEF table
        S2_PON_IRS_DELTA,  //3 bit signed, subtract from AWGN IRS when Pilot On
        S2_PON_PRS_DELTA,  //3 bit signed, subtract from AWGN PRS when Pilot On
        S2_LOOP_COEF_SET,  //3 bit, select one set from the CLIP_PED table
        S2_CLIP_PED_SET,   //3 bit, select one set from the CLIP_PED table
        S2_AVG_PED_SET,    //3 bit, select one set from the AVG_PED table
        S2_FORCE_OLD_CR,   //1 bit, only affect pilot off
        S2_LLR_SHIFT ,             //1 bit
        } 
	*/
        // enable MERGE_ROUND
        nim_reg_read(dev,0x137,&rdata,1);
        rdata |=0x20;
        nim_reg_write(dev,0x137,&rdata,1);
        nim_reg_read(dev,0x113,&reg_llr_shift,1);
		reg_llr_shift |= 0x80;
		nim_reg_write(dev,0x113,&reg_llr_shift,1);
		for(CellID=0; CellID<28; CellID++)
		{
	//		CellID=11;
			TabID =  0;
			S2_CODE_RATE_TABLE[CellID]=((((S2_AWGN_NOISE[CellID])<<1) & 0x00000ffe)<<20) | // why?
								((S2_AWGN_COEF_SET[CellID] & 0x00000007)<<17) | 
								((S2_PON_IRS_DELTA[CellID] & 0x00000007)<<14) | 
								((S2_PON_PRS_DELTA[CellID] & 0x00000007)<<11) | 
								((S2_LOOP_COEF_SET[CellID] & 0x00000007)<<8) | 
								((S2_CLIP_PED_SET[CellID] & 0x00000007)<<5) | 
								((S2_AVG_PED_SET[CellID] & 0x00000007)<<2) | 
								((S2_FORCE_OLD_CR[CellID] & 0x00000001)<<1) | 
								0x00000001;
			//step 1: 
			data=(TabID<<5) | (CellID & 0x1f);
			nim_reg_write(dev,R9D_RPT_DEMAP_BETA,&data,1 );

			//step 2:
			TabVal_14_0 = (UINT16)((S2_CODE_RATE_TABLE[CellID]  & 0x7fff));	// and disable the CR_PARA_WE to avoid disturb with seen's adpt
			DatArray[0]=(UINT8)TabVal_14_0;
			DatArray[1]=((UINT8)(TabVal_14_0>>8)) & 0x7f;
			nim_reg_write(dev,R11_DCC_OF_I, DatArray, 2);

			//step 3:
			TavVal_29_15 = (UINT16)(S2_CODE_RATE_TABLE[CellID]>>15);
			DatArray[0]=(UINT8)(TavVal_29_15);
			DatArray[1]=(UINT8)(TavVal_29_15>>8) | 0x80;  // enable CR_PARA_WE_2
			nim_reg_write(dev,R130_CR_PARA_DIN,DatArray,2);	
		}

		for(CellID=0; CellID<5; CellID++)
		{
//		CellID=11;
		TabID =  5;
		S_CODE_RATE_TABLE[CellID]=((((S_AWGN_NOISE[CellID])<<1) & 0x00000ffe)<<20) | // why?
								((S_AWGN_COEF_SET[CellID] & 0x00000007)<<17) | 
								((S_PON_IRS_DELTA[CellID] & 0x00000007)<<14) | 
								((S_PON_PRS_DELTA[CellID] & 0x00000007)<<11) | 
								((S_LOOP_COEF_SET[CellID] & 0x00000007)<<8) | 
								((S_CLIP_PED_SET[CellID] & 0x00000007)<<5) | 
								((S_AVG_PED_SET[CellID] & 0x00000007)<<2) | 
								((S_FORCE_OLD_CR[CellID] & 0x00000001)<<1) | 
								0x00000001;
		//step 1: 
		data=(TabID<<5) | (CellID & 0x1f);
		nim_reg_write(dev,R9D_RPT_DEMAP_BETA,&data,1 );

		//step 2:
		TabVal_14_0 = (UINT16)((S_CODE_RATE_TABLE[CellID]  & 0x7fff));	// and disable the CR_PARA_WE to avoid disturb with seen's adpt
		DatArray[0]=(UINT8)TabVal_14_0;
		DatArray[1]=((UINT8)(TabVal_14_0>>8)) & 0x7f;
		nim_reg_write(dev,R11_DCC_OF_I, DatArray, 2);

		//step 3:
		TavVal_29_15 = (UINT16)(S_CODE_RATE_TABLE[CellID]>>15);
		DatArray[0]=(UINT8)(TavVal_29_15);
		DatArray[1]=(UINT8)(TavVal_29_15>>8) | 0x80;  // enable CR_PARA_WE_2
		nim_reg_write(dev,R130_CR_PARA_DIN,DatArray,2);	
		}
	}
	else
	{
    // disable MERGE_ROUND
        nim_reg_read(dev,0x137,&rdata,1);
        rdata &=0xcf;
        nim_reg_write(dev,0x137,&reg_llr_shift,1);
        nim_reg_read(dev,0x113,&reg_llr_shift,1);
		reg_llr_shift &= 0x7f;
		nim_reg_write(dev,0x113,&reg_llr_shift,1);
		for(CellID=0; CellID<28; CellID++)
		{
	//		CellID=11;
			TabID =  0;
			S2_CODE_RATE_TABLE[CellID]=((((S2_AWGN_NOISE[CellID])<<1) & 0x00000ffe)<<20) | // why?
								((S2_AWGN_COEF_SET[CellID] & 0x00000007)<<17) | 
								((S2_PON_IRS_DELTA[CellID] & 0x00000007)<<14) | 
								((S2_PON_PRS_DELTA[CellID] & 0x00000007)<<11) | 
								((S2_LOOP_COEF_SET[CellID] & 0x00000007)<<8) | 
								((S2_CLIP_PED_SET[CellID] & 0x00000007)<<5) | 
								((S2_AVG_PED_SET[CellID] & 0x00000007)<<2) | 
								((S2_FORCE_OLD_CR[CellID] & 0x00000001)<<1) | 
								0x00000000;
			//step 1: 
			data=(TabID<<5) | (CellID & 0x1f);
			nim_reg_write(dev,R9D_RPT_DEMAP_BETA,&data,1 );

			//step 2:
			TabVal_14_0 = (UINT16)((S2_CODE_RATE_TABLE[CellID]  & 0x7fff));	// and disable the CR_PARA_WE to avoid disturb with seen's adpt
			DatArray[0]=(UINT8)TabVal_14_0;
			DatArray[1]=((UINT8)(TabVal_14_0>>8)) & 0x7f;
			nim_reg_write(dev,R11_DCC_OF_I, DatArray, 2);

			//step 3:
			TavVal_29_15 = (UINT16)(S2_CODE_RATE_TABLE[CellID]>>15);
			DatArray[0]=(UINT8)(TavVal_29_15);
			DatArray[1]=(UINT8)(TavVal_29_15>>8) | 0x80;  // enable CR_PARA_WE_2
			nim_reg_write(dev,R130_CR_PARA_DIN,DatArray,2);	
		}
		for(CellID=0; CellID<5; CellID++)
		{
//		CellID=11;
		TabID =  5;
		S_CODE_RATE_TABLE[CellID]=((((S_AWGN_NOISE[CellID])<<1) & 0x00000ffe)<<20) | // why?
								((S_AWGN_COEF_SET[CellID] & 0x00000007)<<17) | 
								((S_PON_IRS_DELTA[CellID] & 0x00000007)<<14) | 
								((S_PON_PRS_DELTA[CellID] & 0x00000007)<<11) | 
								((S_LOOP_COEF_SET[CellID] & 0x00000007)<<8) | 
								((S_CLIP_PED_SET[CellID] & 0x00000007)<<5) | 
								((S_AVG_PED_SET[CellID] & 0x00000007)<<2) | 
								((S_FORCE_OLD_CR[CellID] & 0x00000001)<<1) | 
								0x00000000;
		//step 1: 
		data=(TabID<<5) | (CellID & 0x1f);
		nim_reg_write(dev,R9D_RPT_DEMAP_BETA,&data,1 );

		//step 2:
		TabVal_14_0 = (UINT16)((S_CODE_RATE_TABLE[CellID]  & 0x7fff));	// and disable the CR_PARA_WE to avoid disturb with seen's adpt
		DatArray[0]=(UINT8)TabVal_14_0;
		DatArray[1]=((UINT8)(TabVal_14_0>>8)) & 0x7f;
		nim_reg_write(dev,R11_DCC_OF_I, DatArray, 2);

		//step 3:
		TavVal_29_15 = (UINT16)(S_CODE_RATE_TABLE[CellID]>>15);
		DatArray[0]=(UINT8)(TavVal_29_15);
		DatArray[1]=(UINT8)(TavVal_29_15>>8) | 0x80;  // enable CR_PARA_WE_2
		nim_reg_write(dev,R130_CR_PARA_DIN,DatArray,2);	
	}
	}
	
	}
	return SUCCESS;
}

static INT32 nim_s3503_cr_adaptive_method_choice(struct nim_device *dev, UINT8 choice_type)
{
/******************************************************************************
	* choice_type = 0: only choice NEW CR ADPT method
	* choice_type = 1: only choice OLD CR ADPT method
	* choice_type = 2: part choice NEW CR ADPT and part choice OLD ADPT method
	* choice_type = 3: using the value of regfile
******************************************************************************/
/*
			ADPT_CR_METHOD_CHOICE_2_ALL=0	reg_cr13a[4]=0
			ADPT_CR_METHOD_CHOICE_1_ALL=0	reg_cr13a[5]=0
			ADPT_CR_PARA_EN1 = 1		reg_cr113[1]=1	
*/
	UINT8 rdata;
	switch(choice_type)// only choice NEW CR ADPT method
	{
    case 0:
		nim_reg_read(dev,0x13a, &rdata,1);
		rdata |= 0x10;
		nim_reg_write(dev,0x13a, &rdata,1);
		nim_reg_read(dev,0x113, &rdata,1);
		rdata |= 0x02;
		nim_reg_write(dev,0x113, &rdata,1);
		break;
	case 1: //only choice OLD CR ADPT method
		nim_reg_read(dev,0x13a, &rdata,1);
		rdata |= 0x20;
		rdata &= 0xef;
		nim_reg_write(dev,0x13a, &rdata,1);
		nim_reg_read(dev,0x12e,&rdata,1);// ap1e=0 ap2e=0
        rdata &=0xcf;
        nim_reg_write(dev,0x12e,&rdata,1);
        nim_reg_read(dev,0x137,&rdata,1);//cp1e=0 cp2e=0
        rdata &=0xee;
        nim_reg_write(dev,0x137,&rdata,1);
        nim_reg_read(dev,0x113, &rdata,1);
		rdata |= 0x02;
		nim_reg_write(dev,0x113, &rdata,1);
		break;
	case 2:// if you want to use this circumstance, you need to edit again
		nim_reg_read(dev,0x13a, &rdata,1);
		rdata &= 0xcf;
		nim_reg_write(dev,0x13a, &rdata,1);
		nim_reg_read(dev,0x113, &rdata,1);
		rdata |= 0x02;
		nim_reg_write(dev,0x113, &rdata,1);
		// you need edit begin here
		//
		//ADPT_CR_METHOD_CHOICE[i] = 1 or 0
		//
		break;
	case 3://using the value of regfile
		nim_reg_read(dev,0x13a, &rdata,1);
		rdata |= 0x10;
		nim_reg_write(dev,0x13a, &rdata,1);
		nim_reg_read(dev,0x113, &rdata,1);
		rdata &= 0xfd;
		nim_reg_write(dev,0x113, &rdata,1);
		break;
	default:// choice NEW CR ADPT method
		nim_reg_read(dev,0x13a, &rdata,1);
		rdata |= 0x10;
		nim_reg_write(dev,0x13a, &rdata,1);
		nim_reg_read(dev,0x113, &rdata,1);
		rdata |= 0x02;
		nim_reg_write(dev,0x113, &rdata,1);
		break;
	}
	return SUCCESS;
}
/*****************************************************************************
* static void nim_c3503_cr_new_adaptive_monitor(struct nim_device *dev)
* Get main parameters of CR and give snr_est value to estimate c/n
* 
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static void nim_s3503_cr_new_adaptive_monitor(struct nim_device *dev)
{
	// Adaptive parameter display	// add by hongyu
	/*
	*	these value is that will send to cr module and display here for debug
	*	the whole is 63'bit and 20 parameters
	*	ADPT_PRS_TRA_FRAC[1:0]=
    	*	ADPT_IRS_TRA_FRAC[1:0]=
   	*	ADPT_CR_PRS_TRA_S2[3:0]=
    	*	ADPT_CR_IRS_TRA_S2[4:0]=
    	*	ADPT_CR_HEAD_PED_GAIN[2:0]=
    	*	ADPT_WIDER_LOOP_EN=
    	*	ADPT_FORCE_OLD_CR=
    	*	ADPT_AVG_HEAD_2HALF_EN=
    	*	ADPT_WIDER_IRS_DELTA[2:0]=
    	*	ADPT_WIDER_PRS_DELTA[2:0]=
    	*	ADPT_SYMBOL_BEFORE_HEAD=
    	*	ADPT_LLR_SHIFT=
	*	ADPT_AVG_PED1_EN=
	*	ADPT_AVG_PED1[7:0]=
	*	ADPT_AVG_PED2_EN=
	*	ADPT_AVG_PED2[7:0]= 
	*	ADPT_CLIP_PED1_EN=
	*	ADPT_CLIP_PED1[7:0]=
	*	ADPT_CLIP_PED2_EN=
	*	ADPT_CLIP_PED2[7:0]=
	
	wire [7:0] reg_cr13b = EST_NOISE[7:0];
	wire [7:0] reg_cr13c = {3'b0,EST_NOISE[12:8]};
	wire [7:0] reg_cr13d = {5'b0,
						ADPT_WIDER_LOOP_EN,
						ADPT_SYMBOL_BEFORE_HEAD,
						ADPT_LLR_SHIFT
						};
	wire [7:0] reg_cr13e = {
						ADPT_FORCE_OLD_CR,
						ADPT_WIDER_PRS_DELTA[2:0],
						ADPT_AVG_HEAD_2HALF_EN,
						ADPT_WIDER_IRS_DELTA[2:0]
						};
	wire [7:0] reg_cr13f = {
						ADPT_CR_PRS_TRA_S2[3:0],
						ADPT_PRS_TRA_FRAC[1:0],
						ADPT_IRS_TRA_FRAC[1:0]
						};
	wire [7:0] reg_cr140 = {
						ADPT_CR_IRS_TRA_S2[4:0],
						ADPT_CR_HEAD_PED_GAIN[2:0]
						};
	wire [7:0] reg_cr141 = {4'b0,
						ADPT_CLIP_PED2_EN,
						ADPT_CLIP_PED1_EN,
						ADPT_AVG_PED2_EN,
						ADPT_AVG_PED1_EN
						};
	wire [7:0] reg_cr142 = ADPT_AVG_PED1[7:0];
	wire [7:0] reg_cr143 = ADPT_AVG_PED2[7:0];
	wire [7:0] reg_cr144 = ADPT_CLIP_PED1[7:0];
	wire [7:0] reg_cr145 = ADPT_CLIP_PED2[7:0];


	*/
/*
	R13b_EST_NOISE = 0x13b,
	R13d_ADPT_CR_PARA_0 = 0x13d,
	R140_ADPT_CR_PARA_1 = 0x140,
	R144_ADPT_CR_PARA_2 = 0x144,
*/
	//UINT8 ap1e,ap2e,cp1e,cp2e;
	//UINT8 cp2, cp1, ap2,ap1,ls,sbh,wle,wid,ah2e,wpd,old,itf,ptf,p,hpg,i;

	UINT8 rdata[4];
	
	nim_reg_read(dev,R13d_ADPT_CR_PARA_0,rdata,3);
	// reg_cr13d
	UINT8 ADPT_LLR_SHIFT=rdata[0] & 0x01;//ls .
	UINT8 ADPT_SYMBOL_BEFORE_HEAD=(rdata[0] >> 1) & 0x01;//sbh .
	UINT8 ADPT_WIDER_LOOP_EN=(rdata[0] >> 2) & 0x01;//wle .
	// reg_cr13e
	UINT8 ADPT_WIDER_IRS_DELTA=rdata[1] & 0x07;//wid .
	UINT8 ADPT_AVG_HEAD_2HALF_EN=(rdata[1] >> 3) & 0x01;//ah2e .
	UINT8 ADPT_WIDER_PRS_DELTA=(rdata[1] >> 4) & 0x07;//wpd .
	UINT8 ADPT_FORCE_OLD_CR=(rdata[1] >> 7) & 0x01;//old .
	// reg_cr13f
	UINT8 ADPT_IRS_TRA_FRAC=rdata[2] & 0x03;//itf .
	UINT8 ADPT_PRS_TRA_FRAC=(rdata[2] >> 2) & 0x03;//ptf .
	UINT8 ADPT_CR_PRS_TRA_S2=(rdata[2] >> 4) & 0x0f;//p .

	nim_reg_read(dev,R140_ADPT_CR_PARA_1,rdata,4);
	// reg_cr140
	UINT8 ADPT_CR_HEAD_PED_GAIN=rdata[0] & 0x07;//hpg .
	UINT8 ADPT_CR_IRS_TRA_S2=(rdata[0] >> 3) & 0x1f;
	//// reg_cr141
    UINT8 adpt_avg_ped1_en = rdata[1] & 0x01; //ap1e .
	UINT8 adpt_avg_ped2_en = (rdata[1] >> 1) & 0x01;//ap2e .
	UINT8 adpt_clip_ped1_en	= (rdata[1] >> 2) & 0x01;//cp1e .
	UINT8 adpt_clip_ped2_en	=(rdata[1] >> 3) & 0x01;//cp2e .
	// reg_cr142 & reg_cr143
	UINT8 adpt_avg_ped1=rdata[2];//ap1 .
	UINT8 adpt_avg_ped2=rdata[3];//ap2 .

	nim_reg_read(dev,R144_ADPT_CR_PARA_2,rdata,2);
	// reg_cr144 & reg_cr145
	UINT8 adpt_clip_ped1=rdata[0];//cp1.
	UINT8 adpt_clip_ped2=rdata[1];//cp2 .
	

ADPT_NEW_CR_PRINTF("p=%x i=%x ptf=%x itf=%x ap1e=%x ap1=%x ap2e=%x ap2=%x cp1e=%x cp1=%x cp2e=%x cp2=%x hpg=%x sbh=%x ah2e=%x ls=%x old=%x wpd=%x wid=%x wle=%x\n",
				ADPT_CR_PRS_TRA_S2,
				ADPT_CR_IRS_TRA_S2,
				ADPT_PRS_TRA_FRAC,
				ADPT_IRS_TRA_FRAC,
				adpt_avg_ped1_en,
				adpt_avg_ped1,
				adpt_avg_ped2_en,
				adpt_avg_ped2,
				adpt_clip_ped1_en,
				adpt_clip_ped1,
				adpt_clip_ped2_en,
				adpt_clip_ped2,
				ADPT_CR_HEAD_PED_GAIN,
				ADPT_SYMBOL_BEFORE_HEAD,
				ADPT_AVG_HEAD_2HALF_EN,
				ADPT_LLR_SHIFT,
				ADPT_FORCE_OLD_CR,
				ADPT_WIDER_PRS_DELTA,
				ADPT_WIDER_IRS_DELTA,
				ADPT_WIDER_LOOP_EN
				);
    #ifdef NEW_CR_ADPT_SNR_EST_RPT
    //nim_c3503_get_snr_cn(dev);
    #endif
		
}

/*****************************************************************************
* static INT32 nim_s3503_get_snr_db(struct nim_device *dev)
* Get estimated CNR in unit 0.01dB from CR new adaptive 
*
* Arguments:
*  Parameter1: struct nim_device *dev
*
* Return Value: UINT16
*****************************************************************************/

static INT32 nim_s3503_get_snr_db(struct nim_device *dev,UINT16 *snr_db)
{
///// display est_noise and then return the current c/n value
	/*
		wire [7:0] reg_cr13b = EST_NOISE[7:0];
		wire [7:0] reg_cr13c = {3'b0,EST_NOISE[12:8]};
		but here only use EST_NOISE[12:3]
	*/
	UINT16 linear_cn=1 ;
	UINT16 diff_cn=0;
	UINT16 ref_est_noise=0 ;
	UINT16 ref_cn=0;	
	UINT8 rdata[2];
	UINT16 rdata16 = 0;
	UINT16 est_noise_1 = 0; // here must be test again
  	UINT8 modu=0 ;  
    UINT16 snr_cn = 0;  
    
	nim_reg_read(dev,R13b_EST_NOISE,rdata,2);
	rdata16 = rdata[1];
	est_noise_1 = (rdata[0] | (rdata16 << 8)) >> 4; // here must be test again
	ADPT_NEW_CR_PRINTF("EST_NOISE=%d--0x%x\n",est_noise_1,est_noise_1);
	nim_reg_read(dev,RF8_MODCOD_RPT,&modu,1);
	modu = (modu & 0x7f)>>2;
    switch(modu)
    {
        case 0: ADPT_NEW_CR_PRINTF("unknown constellation\n");
                break;
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
        case 6:
        case 7:
        case 8:
        case 9:
        case 10:
        case 11: // QPSK
                ADPT_NEW_CR_PRINTF("QPSK\n");
             if(est_noise_1>221)	//8.0dB because when c/n>8.0dB, estimate c/n error is bigger than 0.4dB
			 {
				 linear_cn = 196;
				 diff_cn = 5;
				 ref_est_noise = 47900; // QPSK, 2.0 AWGN frequency=1000M, 5Msymbol rate; roll off=0.35;pilot off;1/2code rate
				 ref_cn = 200;
			 }
			 else
			 {
				 linear_cn = 155;
				 diff_cn = 5;
				 ref_est_noise = 22100; // QPSK, 8.1dB AWGN frequency=1000M, 5Msymbol rate; roll off=0.35;pilot off;1/2code rate
				 ref_cn = 810;
			 }
             break;
       case 12:
       case 13:
       case 14:
       case 15:
       case 16:
       case 17:  // 8PSK
                ADPT_NEW_CR_PRINTF("8PSK\n");
                linear_cn = 100;
				diff_cn = 5;
				ref_est_noise = 21500; // 8psk, 6.0 AWGN frequency=1000M, 5Msymbol rate; roll off=0.35;pilot off;3/5code rate
				ref_cn = 600;
                break;
       case 18:
       case 19:
       case 20:
       case 21:
       case 22:
       case 23: // 16APSK
                ADPT_NEW_CR_PRINTF("16PSK\n");
                if(est_noise_1 > 96)
					{
						linear_cn = 50;
						diff_cn = 5;
						ref_est_noise = 11300; // 10.0 AWGN frequency=1000M, 5Msymbol rate; roll off=0.35;pilot off;2/3code rate
						ref_cn = 1000;
					}
				else
					{
						linear_cn = 51;
						diff_cn = 5;
						ref_est_noise = 9600; // 11.4 AWGN frequency=1000M, 5Msymbol rate; roll off=0.35;pilot off;2/3code rate
						ref_cn = 1150;
					}
                break;
        case 24:
        case 25:
        case 26:
        case 27://32APSK
                    ADPT_NEW_CR_PRINTF("32PSK,24->28 \n");
                    linear_cn = 25;
					diff_cn = 5;
					ref_est_noise = 5400; // 14 AWGN frequency=1000M, 5Msymbol rate; roll off=0.35;pilot off;3/4code rate
					ref_cn = 1400;
                    break;
        case 28:    // 32APSK
                    ADPT_NEW_CR_PRINTF("32PSK,28\n");
                    linear_cn = 25;
					diff_cn = 5;
					ref_est_noise = 3700; // 17 AWGN frequency=1000M, 5Msymbol rate; roll off=0.35;pilot off;9/10code rate
					ref_cn = 1700;
                    break;
         default:   break;                
    }
   snr_cn = ((ref_est_noise-est_noise_1*100)/linear_cn) * diff_cn + ref_cn; // the current c/n value X10	
   ADPT_NEW_CR_PRINTF("c/n=%d\n",snr_cn);
   *snr_db=snr_cn;
     return SUCCESS;
}


/*****************************************************************************
* static void nim_s3503_cr_adaptive_monitor(struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static void nim_s3503_cr_adaptive_monitor(struct nim_device *dev)
{

	static UINT8 interval_cnt = 0;
	UINT8 data,  cr_prs, snr_idx, cr_irs, cr_frac,head_gain;
	UINT32 rdata=0;

	if(interval_cnt==0)
	{
        UINT8 data1=0xe6;
		nim_reg_write(dev,0x0e,&data1,1);
        //ByteDat = ReadMemB(0x180030bc);
		nim_reg_read(dev, RBB_SNR_RPT1, &data, 1);
		rdata = data;
		nim_reg_read(dev, RBC_SNR_RPT2, &data, 1);
		rdata |= data<<8;
		nim_reg_read(dev, R26_TR_LD_LPF_OPT, &data, 1);
		rdata |= data<<16;
		//if(rdata != old_cr_para)
		//{
		//	old_cr_para = rdata;	
            cr_prs =(UINT8)((rdata>>9) & 0xf);
			cr_irs =(UINT8)((rdata>>4) & 0x1f);
			cr_frac = (UINT8)((rdata>>2) & 3);
			head_gain =  (UINT8)((rdata>>13) & 7);
			 
			//if(cr_irs<=6)
			//	cr_irs += 16;

			//if(cr_prs<4)
			//	cr_prs += 8;

			snr_idx =(UINT8) ((rdata>>16) & 0x1f);
            
		if((rdata & 1))
		{
			ADPT_CR_PRINTF("OLDCR \n");
		}
            ADPT_CR_PRINTF("SNR is:%d/10 dB, ",SNR_dBX10_TAB[snr_idx]);
			ADPT_CR_PRINTF("head_gain=%d, cr_prs=0x%x, cr_irs=0x%x, cr_frac=%d, wider_loop=%d\n",head_gain, cr_prs,cr_irs,cr_frac,(rdata>>1 & 1));
          	interval_cnt=6;
	}
	interval_cnt--;

    #ifdef RPT_CR_SNR_EST
		UINT8 ByteDat;
		UINT16 SNR_EST;
		//nim_reg_read(dev,0xe7,ByteDat,1);
		//ByteDat |= 0x80;
		//nim_reg_write(dev,0xe7, &ByteDat,1);
		ADPT_CR_PRINTF("\t\tenter RPT_CR_SNR_EST block\n");
		ByteDat=0xe4;// ADPT_CR_DEBUG=0
		nim_reg_write(dev,0x0e,&ByteDat,1);
		
		nim_reg_read(dev,0xbc,&ByteDat,1);
		ByteDat &= 0x7f; // reg_crbc[7]=0
		nim_reg_write(dev,0xbc,&ByteDat,1);
		//if (ByteDat & 0x80)
		{
			//NIM_PRINTF("\tenter the if block");
			nim_reg_read(dev,0xbc,&ByteDat,1);
			 SNR_EST = (ByteDat & 0x1f) << 6;
			nim_reg_read(dev,0xbb,&ByteDat,1);	
			
			SNR_EST += (ByteDat>>2) & 0x03f;
			ByteDat=0x00;
			nim_reg_write(dev,0xbc, &ByteDat,1);
			
			//if(var>var_max)
				//var_max=var;
		//	if(var<var_min)
			//	var_min = var;
			ADPT_CR_PRINTF("SNR_EST=%d\n",SNR_EST);
		}
		//nim_reg_read(dev,0xe7,ByteDat,1);
		//ByteDat &= 0x7f;
		//nim_reg_write(dev,0xe7, &ByteDat,1);
		#endif
};

  /*****************************************************************************
* static INT32 nim_s3503_get_new_BER(struct nim_device *dev, UINT32 *ber)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_get_new_BER(struct nim_device *dev, UINT32 *ber)
{
	UINT8 data;
	UINT32 t_count, myber;
	myber = 0;
	for (t_count = 0; t_count < 200; t_count++)
	{
		nim_reg_read(dev, R76_BIT_ERR + 0x02, &data, 1);
		if ((data & 0x80) == 0)
		{
			myber = data & 0x7f;
			nim_reg_read(dev, R76_BIT_ERR + 0x01, &data, 1);
			myber <<= 8;
			myber += data;
			nim_reg_read(dev, R76_BIT_ERR, &data, 1);
			myber <<= 8;
			myber += data;
			break;
		}
	}
	*ber = myber;

	return SUCCESS;
}

  /*****************************************************************************
* static INT32 nim_s3503_get_new_PER(struct nim_device *dev, UINT32 *per)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_get_new_PER(struct nim_device *dev, UINT32 *per)
{
	UINT8 data;
	UINT32 t_count, myper;

	myper = 0;
	for (t_count = 0; t_count < 200; t_count++)
	{
		nim_reg_read(dev, R79_PKT_ERR + 0x01, &data, 1);
		if ((data & 0x80) == 0)
		{
			myper = data & 0x7f;
			nim_reg_read(dev, R79_PKT_ERR, &data, 1);
			myper <<= 8;
			myper += data;
			break;
		}
	}
	*per = myper;
	//  NIM_PRINTF("!!!!!!!! myPER cost %d time, per = %d\n",t_count,myper);
	return SUCCESS;
}

 /*****************************************************************************
* INT32 nim_s3503_reg_get_freqoffset(struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_reg_get_freqoffset(struct nim_device *dev)
{
	INT32 freq_off;
	UINT8 data[3];
	UINT32 tdata;
	UINT32 temp;
	UINT32  sample_rate;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	nim_s3503_get_dsp_clk(dev, &sample_rate);
        temp = 0;
        nim_reg_read(dev, R69_RPT_CARRIER, data, 3);
        tdata = (data[0] & 0xff) + ((data[1] & 0xff)<<8);
        if ((data[2] & 0x01) == 1)
            temp = (tdata ^ 0xffff) + 1;
        else
            temp = tdata & 0xffff;
        if ((data[2] & 0x01) == 1)
            freq_off = 0 - nim_s3503_multu64div(temp, sample_rate, 92160000); // 92160000 == 90000*1024
        else
            freq_off = nim_s3503_multu64div(temp, sample_rate, 92160000);
        
	return freq_off;
}
 /*****************************************************************************
* void nim_s3503_cap_calculate_energy(struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static  void nim_s3503_cap_calculate_energy(struct nim_device *dev)
{
	INT32 i, j, k, m,n;//,printf_1 = 1;
	INT32 energy_real, energy_imag;//unsigned energy
	INT32 energy;//unsigned energy
	INT32 energy_tmp;
	INT32 fft_I, fft_Q;
	UINT8 data;
	UINT8 *pFFTdata, *pData = &data;
	//UINT8    data_1[2];
	UINT32 OldIDPos, Find11Packet, PacketNum;
	UINT32 NO_S3501ID;
	UINT32 overflow_cnt = 0;
	struct nim_s3501_private *priv = (struct nim_s3501_private *) dev->priv;
	comm_memset(FFT_energy_1024, 0, sizeof(FFT_energy_1024));

	OldIDPos = 0;
	PacketNum = 0;

	for (k = 0; k < 20; k++)
		{
			//  	NIM_PRINTF("k = %d",k);
			if (priv->ul_status.s3501_autoscan_stop_flag)
			{
				return;
			}
			//get FFT result
			NIM_PRINTF("fft_start\n");
			nim_s3503_cap_fft_result_read(dev);
			NIM_PRINTF("fft_end\n");
		//accumulation
		for (i = 0; i < 1024; i++)
		{
			fft_I = priv->ul_status.FFT_I_1024[i];
			fft_Q = priv->ul_status.FFT_Q_1024[i];

			energy_real = fft_I * fft_I;
			energy_imag = fft_Q * fft_Q;
			energy = energy_real + energy_imag;
			//because 20 times of accumulation needed, result will extend 5 bits
			//nevertherless maximum energy of possible signal(eg. 2Msps) is 5 times 				//lessthan theoretic max energy, ie. 2 bits less
			//if x is maximum FFT level, x^2/20 is maximum signal(2Msps) energy level(psd)
			//if we clip the MSB in FFT module(when FFT layer is 5), the maximum energy is  		//x^2/4
			//so we can get above conclusion
			//so we only need to reduce 3 bits LSB of accumulation result
			energy >>= 3;
			j = (i + 511) & 1023;//fold FFT sequence to natural sequence
			//energy_tmp = FFT_energy_1024_tmp[j] + energy;
			//energy_tmp=FFT_energy_1024[j]+energy*20;
			energy_tmp =  energy;
			//  		FFT_energy_1024[j] = fft_I;

			if ((energy_tmp >> 20) & 1)
			{
				FFT_energy_1024_tmp[j] = 1048575;//maximum unsigned value of 20 bits
			}
			else
			{
				FFT_energy_1024_tmp[j] = energy_tmp;
			}
		}
		for(n=0;n<1024;n++)
		{
			FFT_energy_1024[n] += FFT_energy_1024_tmp[n];
		}

	}
}

/*****************************************************************************
* static INT32 nim_s3503_debug_intask(struct nim_device *dev)
* Get bit error ratio
*
* Arguments:
*  Parameter1: struct nim_device *dev
*  Parameter2: UINT16* RsUbc
*
* Return Value: INT32
*****************************************************************************/
static INT32 nim_s3503_debug_intask(struct nim_device *dev)
{
  NIM_PRINTF(" Enter function nim_s3503_debug_intask \n");
   UINT16  snr_db;
#ifdef HW_ADPT_CR
    #ifdef HW_ADPT_CR_MONITOR
        nim_s3503_cr_adaptive_monitor(dev);
    #endif    
    #ifdef HW_ADPT_NEW_CR_MONITOR
        nim_s3503_cr_new_adaptive_monitor(dev);
        #ifdef NEW_CR_ADPT_SNR_EST_RPT
            nim_s3503_get_snr_db(dev,&snr_db);
        #endif
    #endif
    #ifdef LLR_SHIFT_DEBUG
        nim_s3503_fec_llr_shift(dev);
    #endif
#else
    #ifdef SW_ADPT_CR
        #ifdef SW_SNR_RPT_ONLY
            nim_s3503_cr_sw_snr_rpt(dev);
        #else
            nim_s3503_cr_sw_adaptive(dev);
        #endif
    #endif
#endif
}
